[
  {
    "path": ".editorconfig",
    "content": "# See http://editorconfig.org to read about the EditorConfig format.\n# - Automatically supported by VS2017+ and most common IDE or text editors.\n# - For older VS2010 to VS2015, install https://marketplace.visualstudio.com/items?itemName=EditorConfigTeam.EditorConfig\n\n# top-most EditorConfig file\nroot = true\n\n# Default settings:\n# Use 4 spaces as indentation\n[*]\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[src/overlay*{cpp,h}]\nindent_size = 3\n\n[src/{keybinds,vulkan}.{cpp,h}]\nindent_size = 3\n\n[src/mesa/**]\nindent_size = 3\n\n[meson.build]\nindent_size = 2\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/-bug-report----issue.md",
    "content": "---\nname: \"[Bug report] - Issue\"\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n\n⚠️ **Do not report issues for unsupported or old MangoHud versions.**\nPlease verify the issue still occurs on the latest release before submitting.\n\n---\n\n## Describe the bug\nA clear and concise description of what the bug is.\n\n## System information\nPlease provide all relevant details.\n\n- **Linux distribution**\n- **Kernel version**\n- **MangoHud version**\n- **MangoHud config** (attach or paste if non default)\n- **Launch options**\n- **Application or game**\n- **GPU model and driver**\n- **Display server** (X11 or Wayland)\n\n## Expected behavior\nWhat you expected to happen.\n\n## Actual behavior\nWhat actually happened.\n\n## Logs\nInclude log captured with `MANGOHUD_LOG_LEVEL=debug` set\n\nWrap logs in code blocks.\n\n## Screenshots\nIf applicable, add screenshots to help explain the problem.\n\n## Additional context\nAny other information that might be useful.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/workflows/arch-package.yml",
    "content": "name: arch package\n\non:\n  workflow_dispatch:\n\njobs:\n  build-arch-pkg:\n    runs-on: ubuntu-latest\n    container:\n      image: archlinux:latest\n    steps:\n      - name: set git global safe directory\n        run: |\n          pacman -Syu git --noconfirm\n          git config --global --add safe.directory $(realpath .)\n      - uses: actions/checkout@v3\n      - name: Install prerequisites\n        run: |\n          echo \"ParallelDownloads = 10\" >> /etc/pacman.conf\n          echo \"\\n\" && echo \"[multilib]\" >> /etc/pacman.conf\n          echo \"Include = /etc/pacman.d/mirrorlist\" >> /etc/pacman.conf\n          pacman -Syu base-devel sudo meson python-mako glslang hub python-numpy python-matplotlib --noconfirm\n      - name: makepkg\n        run: |\n          useradd -m builduser\n          echo \"builduser ALL=(ALL) NOPASSWD:ALL\" > /etc/sudoers.d/builduser\n          chmod 0440 /etc/sudoers.d/builduser\n          chown -R builduser:builduser pkgbuild\n          cd pkgbuild\n          pkgver=$(git describe --tags | sed -r 's/^v//;s/([^-]*-g)/r\\1/;s/-/./g')\n          sed -i \"s/pkgver=.*/pkgver=$pkgver/g\" PKGBUILD\n          sudo -u builduser -- sh -c \"makepkg -fsCc --noconfirm\"\n      - name: Edit release and add files\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          set -x\n          assets=()\n          for pkg in ./pkgbuild/*mangohud*.tar.zst;\n            do echo $pkg;\n            assets+=(\"-a\" \"$pkg\")\n          done;\n          tag_name=\"${GITHUB_REF##*/}\"\n          hub release edit \"${assets[@]}\" -m \"\" \"$tag_name\"\n"
  },
  {
    "path": ".github/workflows/build-package.yml",
    "content": "name: Build release package\non:\n  release:\n    types: [published]\n\njobs:\n  build:\n    runs-on: ubuntu-24.04\n\n    steps:\n      - uses: actions/checkout@v3\n      - name: Install build tools\n        run: |\n          set -x\n          sudo dpkg --add-architecture i386\n          sudo apt update\n          sudo apt -y install gcc-multilib g++-multilib ninja-build python3-setuptools \\\n                              python3-wheel mesa-common-dev libxnvctrl-dev libdbus-1-dev \\\n                              python3-numpy python3-matplotlib unzip libxkbcommon-dev libwayland-dev wget unzip \\\n                              libxkbcommon-dev:i386 libwayland-dev:i386 gh python3-mako meson pkgconf pkg-config\n          wget https://github.com/KhronosGroup/glslang/releases/download/SDK-candidate-26-Jul-2020/glslang-master-linux-Release.zip\n          unzip glslang-master-linux-Release.zip bin/glslangValidator\n          sudo install -m755 bin/glslangValidator /usr/local/bin/\n          command -v pkg-config && pkg-config --version\n      - name: Prepare Artifact Git Info\n        shell: bash\n        run: |\n          echo \"##[set-output name=branch;]${GITHUB_REF#refs/heads/}\"\n          ARTIFACT_NAME=\"commit-$(git rev-parse --short \"$GITHUB_SHA\")\"\n          if [ ${{ github.event_name == 'pull_request' }} ]; then\n            echo \"##[set-output name=short-sha;]$(git rev-parse --short \"${{ github.event.pull_request.head.sha }}\")\"\n            if [ ! -z \"${{ github.event.pull_request.number }}\" ]; then\n              ARTIFACT_NAME=\"pr-${{ github.event.pull_request.number }}-commit-$(git rev-parse --short \"${{ github.event.pull_request.head.sha }}\")\"\n            fi\n          else\n            echo \"##[set-output name=short-sha;]$(git rev-parse --short \"$GITHUB_SHA\")\"\n          fi\n          echo \"##[set-output name=artifact-metadata;]$ARTIFACT_NAME\"\n      - name: Build and package\n        run: |\n          ./build-source.sh\n          ./build.sh build -Dwerror=true package release\n      - name: Upload assets to release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          tag_name=\"${GITHUB_REF##*/}\"\n          for pkg in ./build/*.tar.*; do\n            gh release upload \"$tag_name\" \"$pkg\" --clobber\n          done\n\n      - name: Upload artifact\n        uses: actions/upload-artifact@v4\n        continue-on-error: true\n        with:\n          name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}}\n          path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz\n          retention-days: 30\n"
  },
  {
    "path": ".github/workflows/build-source.yml",
    "content": "name: Build source tars\non:\n  workflow_dispatch:\n  release:\n    types: [published]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v3\n      - name: Run build-source.sh\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: |\n          set -x\n          sudo apt update\n          sudo apt -y install gcc g++ ninja-build python3-pip python3-setuptools \\\n                         python3-wheel pkg-config mesa-common-dev libx11-dev \\\n                         libxnvctrl-dev libdbus-1-dev glslang-tools hub libxkbcommon-dev \\\n                         libwayland-dev wget unzip python3-mako meson\n          ./build-source.sh\n          assets=()\n          for asset in ./MangoHud-*-Source*.tar.*; do\n            assets+=(\"-a\" \"$asset\")\n          done\n          tag_name=\"${GITHUB_REF##*/}\"\n          hub release edit \"${assets[@]}\" -m \"\" \"$tag_name\"\n          #hub release create \"${assets[@]}\" -m \"$tag_name\" \"$tag_name\"\n      - name: Upload artifact\n        uses: actions/upload-artifact@v4\n        continue-on-error: true\n        with:\n          name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}}\n          path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz\n          retention-days: 30\n"
  },
  {
    "path": ".github/workflows/mingw.yml",
    "content": "name: Mingw build testing\n\non: [push, pull_request]\njobs:\n  build-mingw:\n    runs-on: ubuntu-latest\n    container:\n      image: archlinux:latest\n    steps:\n      - uses: actions/checkout@v3\n      - name: Install prerequisites\n        run: |\n          pacman -Syu mingw-w64-gcc meson python-mako glslang mingw-w64-headers git --noconfirm\n      - name: configure\n        run: meson setup --cross-file mingw64.txt build64\n      - name: build\n        run: ninja -C build64"
  },
  {
    "path": ".github/workflows/param-check.yml",
    "content": "name: param check\n\non:\n  push:\n    paths:\n      - 'src/overlay_params.h'\n      - 'README.md'\n      - 'data/MangoHud.conf'\n\njobs:\n  param-check:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@v3\n    - name: Set up Python\n      uses: actions/setup-python@v4\n      with:\n        python-version: '3.11.2' # Replace with the version of Python you want to use\n    - name: Run Python script\n      run: |\n        cd tests\n        python params.py\n"
  },
  {
    "path": ".github/workflows/ubuntu.yml",
    "content": "name: Ubuntu build testing\n\non: [push, pull_request]\n\njobs:\n  build-test:\n    strategy:\n      matrix:\n        compiler: [clang, gcc]\n        os: [ubuntu-24.04]\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: 'Checkout'\n      uses: actions/checkout@v3\n    - name: 'Install prerequisites'\n      run: |\n        sudo apt-get update\n        sudo apt-get install -y \\\n          appstream \\\n          glslang-tools \\\n          ninja-build \\\n          python3-mako \\\n          python3-setuptools \\\n          python3-wheel \\\n          mesa-common-dev \\\n          libcmocka-dev \\\n          libdbus-1-dev \\\n          libglfw3-dev \\\n          libwayland-dev \\\n          libxnvctrl-dev \\\n          libxkbcommon-dev \\\n          meson\n    - name: 'Install clang'\n      if:  ${{ (matrix.compiler == 'clang') }}\n      run: |\n          sudo apt-get install -y clang\n          echo \"CC=clang\" >> \"$GITHUB_ENV\"\n          echo \"CXX=clang++\" >> \"$GITHUB_ENV\"\n    - name: 'Install gcc'\n      if:  ${{ (matrix.compiler == 'gcc') }}\n      run: |\n          sudo apt-get install -y gcc g++\n          echo \"CC=gcc\" >> \"$GITHUB_ENV\"\n          echo \"CXX=g++\" >> \"$GITHUB_ENV\"\n    - name: 'Configure'\n      run: meson setup ./builddir --prefix=/usr\n          -D include_doc=true\n          -D with_xnvctrl=enabled\n          -D with_x11=enabled\n          -D with_wayland=enabled\n          -D with_dbus=enabled\n          -D mangoapp=true\n          -D mangohudctl=true\n          -D tests=enabled\n          --werror\n    - name: 'Build'\n      run: meson compile -C ./builddir || ninja -C ./builddir\n    - name: 'Install'\n      run: sudo meson install -C ./builddir\n"
  },
  {
    "path": ".gitignore",
    "content": "build\nbuilddir\n__pycache__\n.vscode\nMangoHud*.tar.*\npkg\nmangohud*.tar.*\nlib32-mangohud*.tar.*\n\n# 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# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n# subprojects\nsubprojects/packagecache/\nsubprojects/Vulkan-Headers-*/\nsubprojects/Vulkan-Utility-Libraries-*/\nsubprojects/imgui-*/\nsubprojects/spdlog-*/\nsubprojects/nlohmann_json-*/\nsubprojects/implot-*/\nsubprojects/cmocka/\n\n#GNU Global Metadata\n**/GPATH\n**/GRTAGS\n**/GTAGS\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"modules/minhook\"]\n\tpath = modules/minhook\n\turl = https://github.com/flightlessmango/minhook\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 flightlessmango\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": "# MangoHud\n\nA Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more.\n\n![Example gif showing a standard performance readout with frametimes](assets/overlay_example.gif)\n\n---\n\n- [MangoHud](#mangohud)\n  - [Installation - Build From Source](#installation---build-from-source)\n    - [Dependencies](#dependencies)\n    - [Building with build script](#building-with-build-script)\n  - [Installation - Pre-packaged Binaries](#installation---pre-packaged-binaries)\n    - [GitHub releases](#github-releases)\n    - [Arch-based distributions](#arch-based-distributions)\n    - [Debian, Ubuntu](#debian-ubuntu)\n    - [Fedora](#fedora)\n    - [Solus](#solus)\n    - [openSUSE](#opensuse)\n    - [Flatpak](#flatpak)\n  - [Normal usage](#normal-usage)\n  - [OpenGL](#opengl)\n  - [Hud configuration](#hud-configuration)\n    - [Environment Variables: **`MANGOHUD_CONFIG`**, **`MANGOHUD_CONFIGFILE`**, and **`MANGOHUD_PRESETSFILE`**](#environment-variables)\n  - [Vsync](#vsync)\n    - [OpenGL Vsync](#opengl-vsync)\n    - [Vulkan Vsync](#vulkan-vsync)\n  - [Keybindings](#keybindings)\n  - [Workarounds](#workarounds)\n  - [FPS logging](#fps-logging)\n    - [Online visualization: FlightlessMango.com](#online-visualization-flightlessmangocom)\n    - [Local visualization: `mangoplot`](#local-visualization-mangoplot)\n  - [Metrics support by GPU vendor/driver](#metrics-support-by-gpu-vendordriver)\n\n## Installation - Build From Source\n\n---\n\nIf you wish to compile MangoHud to keep up to date with any changes - first clone this repository and cd into it:\n\n```\ngit clone --recurse-submodules https://github.com/flightlessmango/MangoHud.git\ncd MangoHud\n```\n\nUsing `meson` to install \"manually\":\n\n```\nmeson build\nninja -C build install\n```\n\nBy default, meson should install MangoHud to `/usr/local`. Specify install prefix with `--prefix=/usr` if desired.\nAdd `-Dappend_libdir_mangohud=false` option to meson to not append `mangohud` to libdir if desired (e.g. /usr/local/lib/mangohud).\n\nTo install 32-bit build on 64-bit distro, specify proper `libdir`: `lib32` for Arch, `lib/i386-linux-gnu` on Debian-based distros. RPM-based distros usually install 32-bit libraries to `/usr/lib` and 64-bit to `/usr/lib64`.\nYou may have to change `PKG_CONFIG_PATH` to point to correct folders for your distro.\n\n```\nCC=\"gcc -m32\" \\\nCXX=\"g++ -m32\" \\\nPKG_CONFIG_PATH=\"/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig\" \\\nmeson build32 --libdir lib32\nninja -C build32 install\n```\n\n### Dependencies\n\nInstall necessary development packages.\n\n- gcc, g++\n- or gcc-multilib, g++-multilib for 32-bit support\n- meson >=0.54\n- ninja (ninja-build)\n- glslang\n- libGL/libEGL (libglvnd, mesa-common-dev, mesa-libGL-devel etc)\n- X11 (libx11-dev)\n- XNVCtrl (libxnvctrl-dev), optional, use `-Dwith_xnvctrl=disabled` option with `meson` to disable\n- D-Bus (libdbus-1-dev), optional, use `-Dwith_dbus=disabled` option with `meson` to disable\n- wayland-client\n- xkbcommon\n\nPython 3 libraries:\n\n- Mako (python3-mako or install with `pip`)\n\nIf distro's packaged `meson` is too old and gives build errors, install newer version with `pip` (`python3-pip`).\n\n### Meson options\n\n| Option        | Default | Description\n| --------      | ------- | -\n| with_nvml     | enabled    |Required for NVIDIA GPU metrics on wayland\n| with_xnvctrl  | enabled    |Required for NVIDIA GPU metrics on older GPUs\n| with_x11      | enabled    |Required for keybinds on x11\n| with_wayland  | enabled    |Required for keybinds on wayland\n| with_dbus     | enabled    |Required for using the media features\n| mangoapp      | false      |Includes mangoapp\n| mangohudctl   | false      |Include mangohudctl\n| tests         | auto       |Includes tests\n| mangoplot     | true       |Includes mangoplot\n\n\n### Building with build script\n\nYou can also use `build.sh` script to do some things automatically like install dependencies, if distro is supported but it usually assumes you are running on x86_64 architecture.\n\nTo just build it, execute:\n\n```\n./build.sh build\n```\n\nYou can also pass arguments to meson:\n\n```\n./build.sh build -Dwith_xnvctrl=disabled\n```\n\nResulting files will be install to `./build/release` folder.\n\nIf you have compiled MangoHud from source, to install it, execute:\n\n```\n./build.sh install\n```\n\nYou can then subsequently uninstall MangoHud via the following command\n\n```\n./build.sh uninstall\n```\n\nTo tar up the resulting binaries into a package and create a release tar with installer script, execute:\n\n```\n./build.sh package release\n```\n\nor combine the commands, although `package` should also call `build` if it doesn't find the built libs:\n\n```\n./build.sh build package release\n```\n\nIf you have built MangoHud before and suddenly it fails, you can try cleaning the `build` folder, execute:\n\n```\n./build.sh clean\n```\n\nCurrently it just does `rm -fr build` and clears subprojects.\n\n__NOTE: If you are running an Ubuntu-based, Arch-based, Fedora-based, or openSUSE-based distro, the build script will automatically detect and prompt you to install missing build dependencies. If you run into any issues with this please report them!__\n\n## Installation - Pre-packaged Binaries\n\n---\n\n### GitHub releases\n\nIf you do not wish to compile anything, simply download the file under [Releases](https://github.com/flightlessmango/MangoHud/releases), extract it, and from within the extracted folder in terminal, execute:\n\n```\n./mangohud-setup.sh install\n```\n\n### Arch-based distributions\n\nIf you are using an Arch-based distribution, install [`mangohud`](https://archlinux.org/packages/extra/x86_64/mangohud/) and [`lib32-mangohud`](https://archlinux.org/packages/multilib/x86_64/lib32-mangohud/) from the `extra`/`multilib` repository. [`mangohud-git`](https://aur.archlinux.org/packages/mangohud-git/) and [`lib32-mangohud-git`](https://aur.archlinux.org/packages/lib32-mangohud-git/) are available on the AUR to be installed via your favourite AUR helper. These can help fix issues with the hud not activating when using stable releases from pacman!\n\nIf you are building it by yourself, you need to enable multilib repository, by editing pacman config:\n\n```\nsudo nano /etc/pacman.conf\n```\n\nand uncomment:\n\n```txt\n#[multilib]\n#Include = /etc/pacman.d/mirrorlist\n```\n\nthen save the file and execute:\n\n```\nsudo pacman -Syy\n```\n\n### Debian, Ubuntu\n\nIf you are using Debian 11 (Bullseye) or later, Ubuntu 21.10 (Impish) or later, or distro derived from them, to install the [MangoHud](https://tracker.debian.org/pkg/mangohud) package, execute:\n\n```\nsudo apt install mangohud\n```\n\nOptionally, if you also need MangoHud for 32-bit applications,\non Debian you can execute:\n\n```\nsudo apt install mangohud:i386\n```\n\nThe 32-bit package is not available on Ubuntu.\n\n### Fedora\n\nIf you are using Fedora, to install the [MangoHud](https://src.fedoraproject.org/rpms/mangohud) package, execute:\n\n```\nsudo dnf install mangohud\n```\n\n### Solus\n\nIf you are using Solus, to install [MangoHud](https://dev.getsol.us/source/mangohud/) simply execute:\n\n```\nsudo eopkg it mangohud\n```\n\n### openSUSE\n\nIf you run openSUSE Leap or Tumbleweed you can get Mangohud from the official repositories.\nThere are two packages, [mangohud](https://software.opensuse.org/package/mangohud) for 64bit and [mangohud-32bit](https://software.opensuse.org/package/mangohud-32bit) for 32bit application support.\nTo have Mangohud working for both 32bit and 64bit applications you need to install both packages even on a 64bit operating system.\n\n```\nsudo zypper in mangohud mangohud-32bit\n```\n\nLeap doesn't seem to have the 32bit package.\n\nLeap 15.2\n\n```\nsudo zypper addrepo -f https://download.opensuse.org/repositories/games:tools/openSUSE_Leap_15.2/games:tools.repo\nsudo zypper install mangohud\n```\n\nLeap 15.3\n\n```\nsudo zypper addrepo -f https://download.opensuse.org/repositories/games:tools/openSUSE_Leap_15.3/games:tools.repo\nsudo zypper install mangohud\n```\n\n### Flatpak\n\nIf you are using Flatpaks, you will have to add the [Flathub repository](https://flatpak.org/setup/) for your specific distribution, and then, to install it, execute:\n\nFor flatpak:\n\n```\nflatpak install org.freedesktop.Platform.VulkanLayer.MangoHud\n```\n\nTo enable MangoHud for all Steam games:\n\n```\nflatpak override --user --env=MANGOHUD=1 com.valvesoftware.Steam\n```\n\n## Normal usage\n\n---\n\nTo enable the MangoHud overlay layer for Vulkan and OpenGL, run :\n\n`mangohud /path/to/app`\n\nFor Lutris games, go to the System options in Lutris (make sure that advanced options are enabled) and add this to the `Command prefix` setting:\n\n`mangohud`\n\nFor Steam games, you can add this as a launch option:\n\n`mangohud %command%`\n\nOr alternatively, add `MANGOHUD=1` to your shell profile (Vulkan only).\n\n## OpenGL\n\nOpenGL games may also need `dlsym` hooking, which is now enabled by default. Set the `MANGOHUD_DLSYM` env to `0` to disable like `MANGOHUD_DLSYM=0 %command%` for Steam.\n\nSome Linux native OpenGL games overrides LD_PRELOAD and stops MangoHud from working. You can sometimes fix this by editing LD_PRELOAD in the start script\n`LD_PRELOAD=/path/to/mangohud/lib/`\n\n## gamescope\n\nTo enable mangohud with gamescope you need to install mangoapp.\n`gamescope --mangoapp -- %command%`\n\nUsing normal mangohud with gamescope is not supported.\n\n## Hud configuration\n\nMangoHud comes with a config file which can be used to set configuration options globally or per application. Usually it is installed as `/usr/share/doc/mangohud/MangoHud.conf.example` or [get a copy from here](https://raw.githubusercontent.com/flightlessmango/MangoHud/master/data/MangoHud.conf).\n\nThe priorities of different config files are:\n\n1. `/path/to/application/dir/MangoHud.conf`\n2. Per-application configuration in ~/.config/MangoHud:\n    1. `~/.config/MangoHud/<application_name>.conf` for native applications, where `<application_name>` is the case sensitive name of the executable\n    2. `~/.config/MangoHud/wine-<application_name>.conf` for wine/proton apps, where `<application_name>` is the case sensitive name of the executable without the `.exe` ending\n3. `~/.config/MangoHud/MangoHud.conf`\n\nExample: For Overwatch, this would be `wine-Overwatch.conf` (even though the executable you run from Lutris is `Battle.net.exe`, the actual game executable name is `Overwatch.exe`).\n\nIf you start the game from the terminal with MangoHud enabled (for example by starting Lutris from the terminal), MangoHud will print the config file names it is looking for.\n\nYou can find an example config in /usr/share/doc/mangohud\n\n[GOverlay](https://github.com/benjamimgois/goverlay) is a GUI application that can be used to manage the config\n\n---\n\n### Environment Variables\n\nYou can also customize the hud by using the `MANGOHUD_CONFIG` environment variable while separating different options with a comma. This takes priority over any config file.\n\nYou can also specify configuration file with `MANGOHUD_CONFIGFILE=/path/to/config` for applications whose names are hard to guess (java, python etc).\n\nYou can also specify presets file with `MANGOHUD_PRESETSFILE=/path/to/config`. This is especially useful when running mangohud in a sandbox such as flatpak.\n\nYou can also specify custom hud libraries for OpenGL using `MANGOHUD_OPENGL_LIBS=/path/to/libMangoHud_opengl.so`. This is useful for testing MangoHud without modifying the installation on your system.\n\nA partial list of parameters are below. See the config file for a complete list.\nParameters that are enabled by default have to be explicitly disabled. These (currently) are `fps`, `frame_timing`, `cpu_stats` (cpu load), `gpu_stats` (gpu load), and each can be disabled by setting the corresponding variable to 0 (e.g., fps=0).\n\n| Variable                           | Description                                                                           |\n|------------------------------------|---------------------------------------------------------------------------------------|\n| `af`                               | Anisotropic filtering level. Improves sharpness of textures viewed at an angle `0`-`16` |\n| `alpha`                            | Set the opacity of all text and frametime graph `0.0`-`1.0`                           |\n| `arch`                             | Show if the application is 32- or 64-bit                                              |\n| `autostart_log=`                   | Starts the log after X seconds from mangohud init                                     |\n| `background_alpha`                 | Set the opacity of the background `0.0`-`1.0`                                         |\n| `battery_color`                    | Change the battery text color                                                         |\n| `battery_icon`                     | Display battery icon instead of percent                                               |\n| `battery_watt`                     | Display wattage for the battery option                                                |\n| `battery_time`                     | Display remaining time for battery option                                             |\n| `battery`                          | Display current battery percent and energy consumption                                |\n| `benchmark_percentiles`            | Configure which framerate percentiles are shown in the logging summary. Default is `97,AVG,1,0.1` |\n| `bicubic`                          | Force bicubic filtering                                                               |\n| `blacklist`                        | Add a program to the blacklist. e.g `blacklist=vkcube,WatchDogs2.exe`                 |\n| `cellpadding_y`                    | Set the vertical cellpadding, default is `-0.085` |\n| `control=`                         | Sets up a unix socket with a specific name that can be connected to with mangohud-control.<br>I.e. `control=mangohud` or `control=mangohud-%p` (`%p` will be replaced by process id)    |\n| `core_load_change`                 | Change the colors of cpu core loads, uses the same data from `cpu_load_value` and `cpu_load_change` |\n| `core_load`                        | Display load & frequency per core                                                     |\n| `core_type`                        | Display CPU core type per core. For Intel, it shows which cores are performance and efficient cores, for ARM it shows core codenames like A52, A53, A76, etc...                                                     |\n| `core_bars`                        | Change the display of `core_load` from numbers to vertical bars                       |\n| `cpu_load_change`                  | Change the color of the CPU load depending on load                                    |\n| `cpu_load_color`                   | Set the colors for the gpu load change low, medium and high. e.g `cpu_load_color=0000FF,00FFFF,FF00FF` |\n| `cpu_load_value`                   | Set the values for medium and high load e.g `cpu_load_value=50,90`                    |\n| `cpu_mhz`                          | Show the CPUs current MHz                                                             |\n| `cpu_power`<br>`gpu_power`         | Display CPU/GPU draw in watts                                                         |\n| `cpu_temp`<br>`gpu_temp`<br>`gpu_junction_temp`<br>`gpu_mem_temp`           | Display current CPU/GPU temperature                                                  |\n| `cpu_custom_temp_sensor`           | Use custom hwmon sensor for cpu temperature. e.g `cpu_custom_temp_sensor=cpuss0_2,temp3_input`.|\n| `cpu_text`<br>`gpu_text`           | Override CPU and GPU text. `gpu_text` is a list in case of multiple GPUs              |\n| `cpu_efficiency`                   | Display CPU efficiency in frames per joule                                            |\n| `custom_text_center`               | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` |\n| `custom_text`                      | Display a custom text e.g `custom_text=Fsync enabled`                                 |\n| `debug`                            | Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) |\n| `device_battery_icon`              | Display wirless device battery icon.                                                  |\n| `device_battery`                   | Display wireless device battery percent. Currently supported arguments `gamepad` and `mouse` e.g `device_battery=gamepad,mouse` |\n| `display_server`                   | Display the current display session (e.g. X11 or wayland)                             |\n| `dynamic_frame_timing`             | This changes frame_timing y-axis to correspond with the current maximum and minimum frametime instead of being a static 0-50 |\n| `engine_short_names`               | Display a short version of the used engine (e.g. `OGL` instead of `OpenGL`)           |\n| `engine_version`                   | Display OpenGL or vulkan and vulkan-based render engine's version                     |\n| `exec`                             | Display output of bash command in next column, e.g. `custom_text=/home` , `exec=df -h /home \\| tail -n 1`. Only works with `legacy_layout=0` |\n| `exec_name`                        | Display current exec name                                                             |\n| `fan`                              | Shows the Steam Deck fan rpm                                                          |\n| `fcat`                             | Enables frame capture analysis                                                        |\n| `fcat_overlay_width=`              | Sets the width of fcat. Default is `24`                                               |\n| `fcat_screen_edge=`                | Decides the edge fcat is displayed on. A value between `1` and `4`                    |\n| `font_file_text`                   | Change text font. Otherwise `font_file` is used                                       |\n| `font_file`                        | Change default font (set location to .TTF/.OTF file)                                  |\n| `font_glyph_ranges`                | Specify extra font glyph ranges, comma separated: `korean`, `chinese`, `chinese_simplified`, `japanese`, `cyrillic`, `thai`, `vietnamese`, `latin_ext_a`, `latin_ext_b`. If you experience crashes or text is just squares, reduce font size or glyph ranges |\n| `font_scale=`                      | Set global font scale. Default is `1.0`                                               |\n| `font_scale_media_player`          | Change size of media player text relative to `font_size`                              |\n| `font_size=`                       | Customizable font size. Default is `24`                                               |\n| `font_size_secondary=`             | Customizable font size for secondary metrics. Default is `0.55 * font_size`, except if `no_small_font` is set, in which case the default value is `font_size`          |\n| `font_size_text=`                  | Customizable font size for other text like media metadata. Default is `24`            |\n| `fps_color_change`                 | Change the FPS text color depepending on the FPS value                                |\n| `fps_color=`                       | Choose the colors that the fps changes to when `fps_color_change` is enabled. Corresponds with fps_value. Default is `b22222,fdfd09,39f900`   |\n| `fps_limit_method`                 | If FPS limiter should wait before or after presenting a frame. Choose `late` (default) for the lowest latency or `early` for the smoothest frametimes |\n| `fps_limit`                        | Limit the apps framerate. Comma-separated list of one or more FPS values. `0` means unlimited |\n| `fps_only`                         | Show FPS only. ***Not meant to be used with other display params***                   |\n| `fps_sampling_period=`             | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500`   |\n| `fps_value`                        | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` |\n| `fps_metrics`                      | Takes a list of decimal values or the value avg, e.g `avg,0.001`                      |\n| `reset_fps_metrics`                | Reset fps metrics keybind, default is `Shift_R+F9`                                    |\n| `fps_text`                         | Display custom text for engine name in front of FPS                                   |\n| `frame_count`                      | Display frame count                                                                   |\n| `frametime`                        | Display frametime next to FPS text                                                    |\n| `frame_timing_detailed`            | Display frame timing in a more detailed chart                                         |\n| `fsr`                              | Display the status of FSR (only works in gamescope)                                   |\n| `hdr`                              | Display the status of HDR (only works in gamescope)                                   |\n| `refresh_rate`                     | Display the current refresh rate (only works in gamescope)                            |\n| `full`                             | Enable most of the toggleable parameters (currently excludes `histogram`)             |\n| `gamemode`                         | Show if GameMode is on                                                                |\n| `gpu_color`<br>`cpu_color`<br>`vram_color`<br>`ram_color`<br>`io_color`<br>`engine_color`<br>`frametime_color`<br>`background_color`<br>`text_color`<br>`media_player_color`<br>`network_color`         | Change default colors: `gpu_color=RRGGBB` |\n| `gpu_core_clock`<br>`gpu_mem_clock`| Display GPU core/memory frequency                                                     |\n| `gpu_fan`                          | GPU fan in RPM, except NVIDIA where it is a percentage |\n| `gpu_load_change`                  | Change the color of the GPU load depending on load                                    |\n| `gpu_load_color`                   | Set the colors for the gpu load change low,medium and high. e.g `gpu_load_color=0000FF,00FFFF,FF00FF` |\n| `gpu_load_value`                   | Set the values for medium and high load e.g `gpu_load_value=50,90`                    |\n| `gpu_name`                         | Display GPU name from pci.ids                                                         |\n| `gpu_voltage`                      | Display GPU voltage                                                                   |\n| `gpu_list`                         | List GPUs to display `gpu_list=0,1`                                                   |\n| `gpu_efficiency`                   | Display GPU efficiency in frames per joule                                            |\n| `gpu_power_limit`                  | Display GPU power limit                                                               |\n| `hide_fsr_sharpness`               | Hides the sharpness info for the `fsr` option (only available in gamescope)           |\n| `histogram`                        | Change FPS graph to histogram                                                         |\n| `horizontal`                       | Display Mangohud in a horizontal position                                             |\n| `horizontal_separator_color`       | Set the colors for the horizontal separators (horizontal layout only)                 |\n| `horizontal_stretch`               | Stretches the background to the screens width in `horizontal` mode                    |\n| `hud_compact`                      | Display compact version of MangoHud                                                   |\n| `hud_no_margin`                    | Remove margins around MangoHud                                                        |\n| `io_read`<br> `io_write`           | Show non-cached IO read/write, in MiB/s                                               |\n| `log_duration`                     | Set amount of time the logging will run for (in seconds)                              |\n| `log_interval`                     | Change the default log interval in milliseconds. Default is `0`                       |\n| `log_versioning`                   | Adds more headers and information such as versioning to the log. This format is not supported on flightlessmango.com (yet)    |\n| `media_player_format`              | Format media player metadata. Add extra text etc. Semi-colon breaks to new line. Defaults to `{title};{artist};{album}` |\n| `media_player_name`                | Force media player DBus service name without the `org.mpris.MediaPlayer2` part, like `spotify`, `vlc`, `audacious` or `cantata`. If none is set, MangoHud tries to switch between currently playing players |\n| `media_player`                     | Show media player metadata                                                            |\n| `no_display`                       | Hide the HUD by default                                                               |\n| `no_small_font`                    | Use primary font size for smaller text like units                                     |\n| `offset_x` `offset_y`              | HUD position offsets                                                                  |\n| `output_file`                      | Set location and name of the log file                                                 |\n| `output_folder`                    | Set location of the output files (Required for logging)                               |\n| `pci_dev`                          | Select GPU device in multi-gpu setups                                                 |\n| `permit_upload`                    | Allow uploading of logs to Flightlessmango.com                                        |\n| `picmip`                           | Mip-map LoD bias. Negative values will increase texture sharpness (and aliasing). Positive values will increase texture blurriness `-16`-`16` |\n| `position=`                        | Location of the HUD: `top-left` (default), `top-right`, `middle-left`, `middle-right`, `bottom-left`, `bottom-right`, `top-center`, `bottom-center` |\n| `preset=`                          | Comma separated list of one or more presets. Default is `-1,0,1,2,3,4`. Available presets:<br>`0` (No Hud)<br> `1` (FPS Only)<br> `2` (Horizontal)<br> `3` (Extended)<br> `4` (Detailed)<br>User defined presets can be created by using a [presets.conf](data/presets.conf) file in `~/.config/MangoHud/`.                      |\n| `procmem`<br>`procmem_shared`, `procmem_virt`| Displays process' memory usage: resident, shared and/or virtual. `procmem` (resident) also toggles others off if disabled |\n| `proc_vram`                        | Display process' VRAM usage                                                           |\n| `ram`<br>`vram`                    | Display system RAM/VRAM usage                                                         |\n| `ram_temp`                         | Display RAM temperature (only supports DDR5 with `spd5118` driver)                    |\n| `read_cfg`                         | Add to MANGOHUD_CONFIG as first parameter to also load config file. Otherwise only `MANGOHUD_CONFIG` parameters are used |\n| `reload_cfg=`                      | Change keybind for reloading the config. Default = `Shift_L+F4`                       |\n| `resolution`                       | Display the current resolution                                                        |\n| `retro`                            | Disable linear texture filtering. Makes textures look blocky                          |\n| `round_corners`                    | Change the amount of roundness of the corners have e.g `round_corners=10.0`           |\n| `show_fps_limit`                   | Display the current FPS limit                                                         |\n| `swap`                             | Display swap space usage next to system RAM usage                                     |\n| `table_columns`                    | Set the number of table columns for ImGui, defaults to 3                              |\n| `temp_fahrenheit`                  | Show temperature in Fahrenheit                                                        |\n| `text_outline`                     | Draw an outline around text for better readability. Enabled by default.               |\n| `text_outline_color=`              | Set the color of `text_outline`. Default = `000000`                                   |\n| `text_outline_thickness=`          | Set the thickness of `text_outline`. Default = `1.5`                                  |\n| `throttling_status`                | Show if GPU is throttling based on Power, current, temp or \"other\" (Only shows if throttling is currently happening). Currently disabled by default for Nvidia as it causes lag on 3000 series |\n| `throttling_status_graph`          | Same as `throttling_status` but displays throttling in the frametime graph and only power and temp throttling |\n| `time`<br>`time_format=%T`         | Display local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. NOTE: Sometimes apps may set `TZ` (timezone) environment variable to UTC/GMT |\n| `time_no_label`                    | Remove the label before time                                                          |\n| `toggle_fps_limit`                 | Cycle between FPS limits (needs at least two values set with `fps_limit`). Defaults to `Shift_L+F1`                                    |\n| `toggle_preset`                    | Cycle between Presets. Defaults to `Shift_R+F10`                                      |\n| `toggle_hud=`<br>`toggle_logging=` | Modifiable toggle hotkeys. Default are `Shift_R+F12` and `Shift_L+F2`, respectively   |\n| `toggle_hud_position`              | Toggle MangoHud position. Default is `R_Shift+F11`                                     |\n| `trilinear`                        | Force trilinear filtering                                                             |\n| `upload_log`                       | Change keybind for uploading log                                                      |\n| `upload_logs`                      | Enables automatic uploads of logs to flightlessmango.com                              |\n| `version`                          | Show current MangoHud version                                                         |\n| `vkbasalt`                         | Show if vkBasalt is on                                                                |\n| `vsync`<br> `gl_vsync`             | Set Vsync for OpenGL or Vulkan                                                        |\n| `vulkan_present_mode=<name>`       | Override Vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) using specified mode name (takes precedence over `vsync=`) |\n| `vulkan_driver`                    | Display used Vulkan driver (radv/amdgpu-pro/amdvlk)                                   |\n| `width=`<br>`height=`              | Customizable HUD dimensions (in pixels)                                              |\n| `wine_color`                       | Change color of the wine/proton text                                                  |\n| `wine`                             | Show current Wine or Proton version in use                                            |\n| `winesync`                         | Show wine sync method in use                                                          |\n| `present_mode`                     | Shows current vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) or vsync status in opengl  |\n| `network`                          | Show network interfaces tx and rx kb/s. You can specify interface with `network=eth0` |\n| `fex_stats`                        | Show FEX-Emu statistics. Default = `status+apptype+hotthreads+jitload+sigbus+smc+softfloat` |\n| `ftrace`                           | Display information about trace events reported through ftrace                        |\n| `flip_efficiency`                  | Flips CPU and GPU efficiency to joules per frame                                      |\n\nExample: `MANGOHUD_CONFIG=cpu_temp,gpu_temp,position=top-right,height=500,font_size=32`\nBecause comma is also used as option delimiter and needs to be escaped for values with a backslash, you can use `+` like `MANGOHUD_CONFIG=fps_limit=60+30+0` instead.\n\n*Note: Width and Height are set automatically based on the font_size, but can be overridden.*\n\n*Note: RAPL is currently used for Intel and AMD Zen CPUs to show power draw with `cpu_power` which may be unreadable for non-root users due to [vulnerability](https://platypusattack.com/). The corresponding `energy_uj` file has to be readable by corresponding user, e.g. by running `chmod o+r /sys/class/powercap/intel-rapl\\:0/energy_uj` as root, else the power shown will be **0 W**, though having the file readable may potentially be a security vulnerability persisting until system reboots.*\n\n*Note: The [zenpower3](https://git.exozy.me/a/zenpower3) or [zenergy](https://github.com/boukehaarsma23/zenergy) kernel driver must be installed to show the power draw of Ryzen CPUs.*\n\n## Vsync\n\n### OpenGL Vsync\n\n- `-1` = Adaptive sync\n- `0`  = Off\n- `1`  = On\n- `n`  = Sync to refresh rate / n.\n\n### Vulkan Vsync\n\n- `0` = Adaptive VSync (FIFO_RELAXED_KHR)\n- `1` = Off (IMMEDIATE_KHR)\n- `2` = Mailbox (VSync with uncapped FPS) (MAILBOX_KHR)\n- `3` = On (FIFO_KHR)\n\nNot all vulkan vsync options may be supported on your device, you can check what your device supports here [vulkan.gpuinfo.org](https://vulkan.gpuinfo.org/listsurfacepresentmodes.php?platform=linux)\n\n## Keybindings\n\n- `Shift_L+F2` : Toggle Logging\n- `Shift_L+F4` : Reload Config\n- `Shift_R+F12` : Toggle Hud\n- `Shift_R+F9` : Reset FPS metrics\n\n## Workarounds\n\nOptions starting with \"gl_*\" are for OpenGL.\n\n- `gl_size_query = viewport` : Specify what to use for getting display size. Options are \"viewport\", \"scissorbox\" or disabled. Defaults to using glXQueryDrawable.\n- `gl_bind_framebuffer = 0..N` : (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III.\n- `gl_dont_flip = 1` : Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx.\n\n## FPS logging\n\nYou must set a valid path for `output_folder` in your configuration to store logs in.\n\nWhen you toggle logging (default keybind is `Shift_L+F2`), a file is created with the game name plus a date & timestamp in your `output_folder`.\n\nLog files can be visualized with two different tools: online and locally.\n\n### Online visualization: FlightlessMango.com\nLog files can be (batch) uploaded to [FlightlessMango.com](https://flightlessmango.com/games/user_benchmarks), which will then take care of creating a frametime graph and a summary with 1% min / average framerate / 97th percentile in a table form and a horizontal bar chart form.\n\nNotes:\n- Uploaded benchmarks are public: you can share them with anyone by simply giving them the link.\n- Benchmark filenames are used as legend in the produced tables and graphs, they can be renamed after the upload.\n\n![Gif illustrating the log uploading process](assets/log_upload_example.gif)\n\n### Local visualization: `mangoplot`\n`mangoplot` is a plotting script that is shipped with `MangoHud`: on a given folder, it takes each log file, makes a 1D heatmap of its framerates, then stacks the heats maps vertically to form a 2D graph for easy visual comparison between benchmarks.\n\nExample output:\n\n![Overwatch 2 windows 11 vs linux](assets/Overwatch2-w11-vs-linux.svg)\n\n<sub><sup>Overwatch 2, 5950X + 5700XT, low graphics preset, FHD, 50% render scale</sup></sub>\n\n## Metrics support by GPU vendor/driver\n<table>\n\t<tr>\n\t\t<th></th>\n\t\t<th>Nvidia</th>\n\t\t<th>AMD</th>\n\t\t<th colspan=\"2\">Intel Discrete</th>\n\t\t<th>Intel Integrated</th>\n\t\t<th>Panfrost/Panthor driver</th>\n\t</tr>\n\t<tr>\n\t\t<th></th>\n\t\t<th></th>\n\t\t<th></th>\n\t\t<th>i915</th>\n\t\t<th>xe</th>\n\t\t<th>i915/xe</th>\n\t\t<th></th>\n\t</tr>\n\t<tr>\n\t\t<td>Usage%</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t</tr>\n\t<tr>\n\t\t<td>Temperature</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🟢</td>\n\t</tr>\n\t<tr>\n\t\t<td>Junction Temperature</td>\n\t\t<td>🔴</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Memory Temperature</td>\n\t\t<td>🔴</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Process VRAM</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t</tr>\n\t<tr>\n\t\t<td>System VRAM</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Total VRAM</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Memory Clock</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Core Clock</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t</tr>\n\t<tr>\n\t\t<td>Power Usage</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Throttling Status</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Fan Speed</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n\t<tr>\n\t\t<td>Voltage</td>\n\t\t<td>🔴</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🟢</td>\n\t\t<td>🔴</td>\n\t\t<td>🔴</td>\n\t</tr>\n</table>\n\n#### Intel notes\n- GPU temperature for `i915` requires **linux 6.13+**\n- Fan speed for `i915` requires **linux 6.12+**\n- GPU temperature and vram temperature for `xe` requires **linux 6.15+** \n- Fan speed for `xe` requires **linux 6.16+**\n- GPU usage and memory usage shows usage of current process, not total system usage (it's an issue on intel's side)\n  - https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14153\n  - https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/4861\n- Integrated Intel GPUs are **limited** due to lack of hwmon interface (it's an issue on intel's side, [i915 source](https://github.com/torvalds/linux/blob/5fc31936081919a8572a3d644f3fbb258038f337/drivers/gpu/drm/i915/i915_hwmon.c#L914-L916), [xe source](https://github.com/torvalds/linux/blob/5fc31936081919a8572a3d644f3fbb258038f337/drivers/gpu/drm/xe/xe_hwmon.c#L824-L826))\n\n#### Panfrost and Panthor notes\n- GPU usage requires `echo N | sudo tee /sys/class/drm/renderD*/device/profiling`\n  - Where N is a number, 1 for panfrost and 3 for panthor.\n"
  },
  {
    "path": "bin/gen_enum_to_str.py",
    "content": "# Copyright © 2017 Intel Corporation\n\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n\n# The above copyright notice and this permission notice shall be included in\n# all 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,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n\"\"\"Create enum to string functions for vulkan using vk.xml.\"\"\"\n\nimport argparse\nimport functools\nimport os\nimport re\nimport textwrap\nimport xml.etree.ElementTree as et\n\nfrom mako.template import Template\nfrom vk_extensions import Extension, filter_api, get_all_required\n\nCOPYRIGHT = textwrap.dedent(u\"\"\"\\\n    * Copyright © 2017 Intel Corporation\n    *\n    * Permission is hereby granted, free of charge, to any person obtaining a copy\n    * of this software and associated documentation files (the \"Software\"), to deal\n    * in the Software without restriction, including without limitation the rights\n    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n    * copies of the Software, and to permit persons to whom the Software is\n    * furnished to do so, subject to the following conditions:\n    *\n    * The above copyright notice and this permission notice shall be included in\n    * all 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,\n    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n    * SOFTWARE.\"\"\")\n\nC_TEMPLATE = Template(textwrap.dedent(u\"\"\"\\\n    /* Autogenerated file -- do not edit\n     * generated by ${file}\n     *\n     ${copyright}\n     */\n\n    #include <string.h>\n    #include <vulkan/vulkan_core.h>\n    #include <vulkan/vk_layer.h>\n    #include \"../src/mesa/util/macros.h\"\n    #include \"vk_enum_to_str.h\"\n\n    % for enum in enums:\n\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n    const char *\n    vk_${enum.name[2:]}_to_str(${enum.name} input)\n    {\n        switch((int64_t)input) {\n    % for v in sorted(enum.values.keys()):\n        case ${v}:\n            return \"${enum.values[v]}\";\n    % endfor\n        case ${enum.max_enum_name}: return \"${enum.max_enum_name}\";\n        default:\n            return \"Unknown ${enum.name} value.\";\n        }\n    }\n\n      % if enum.guard:\n#endif\n      % endif\n    %endfor\n\n    % for enum in bitmasks:\n\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n    const char *\n    vk_${enum.name[2:]}_to_str(${enum.name} input)\n    {\n        switch((int64_t)input) {\n    % for v in sorted(enum.values.keys()):\n        case ${v}:\n            return \"${enum.values[v]}\";\n    % endfor\n        default:\n            return \"Unknown ${enum.name} value.\";\n        }\n    }\n\n      % if enum.guard:\n#endif\n      % endif\n    %endfor\n\n    size_t vk_structure_type_size(const struct VkBaseInStructure *item)\n    {\n        switch((int)item->sType) {\n    % for struct in structs:\n        % if struct.extension is not None and struct.extension.define is not None:\n    #ifdef ${struct.extension.define}\n        case ${struct.stype}: return sizeof(${struct.name});\n    #endif\n        % else:\n        case ${struct.stype}: return sizeof(${struct.name});\n        % endif\n    %endfor\n        case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: return sizeof(VkLayerInstanceCreateInfo);\n        case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: return sizeof(VkLayerDeviceCreateInfo);\n        default:\n            UNREACHABLE(\"Undefined struct type.\");\n        }\n    }\n\n    const char *\n    vk_ObjectType_to_ObjectName(VkObjectType type)\n    {\n        switch((int)type) {\n    % for object_type in sorted(object_types[0].enum_to_name.keys()):\n        case ${object_type}:\n            return \"${object_types[0].enum_to_name[object_type]}\";\n    % endfor\n        default:\n            return \"Unknown VkObjectType value.\";\n        }\n    }\n    \"\"\"))\n\nH_TEMPLATE = Template(textwrap.dedent(u\"\"\"\\\n    /* Autogenerated file -- do not edit\n     * generated by ${file}\n     *\n     ${copyright}\n     */\n\n    #ifndef MESA_VK_ENUM_TO_STR_H\n    #define MESA_VK_ENUM_TO_STR_H\n\n    #include <vulkan/vulkan.h>\n    #ifdef __cplusplus\n    extern \"C\" {\n    #endif\n\n    % for enum in enums:\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n    const char * vk_${enum.name[2:]}_to_str(${enum.name} input);\n      % if enum.guard:\n#endif\n      % endif\n    % endfor\n\n    % for enum in bitmasks:\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n    const char * vk_${enum.name[2:]}_to_str(${enum.name} input);\n      % if enum.guard:\n#endif\n      % endif\n    % endfor\n\n    size_t vk_structure_type_size(const struct VkBaseInStructure *item);\n\n    const char * vk_ObjectType_to_ObjectName(VkObjectType type);\n\n    #ifdef __cplusplus\n    } /* extern \"C\" */\n    #endif\n\n    #endif\n    \"\"\"))\n\n\nH_DEFINE_TEMPLATE = Template(textwrap.dedent(u\"\"\"\\\n    /* Autogenerated file -- do not edit\n     * generated by ${file}\n     *\n     ${copyright}\n     */\n\n    #ifndef MESA_VK_ENUM_DEFINES_H\n    #define MESA_VK_ENUM_DEFINES_H\n\n    #include <vulkan/vulkan_core.h>\n    #ifdef __cplusplus\n    extern \"C\" {\n    #endif\n\n    % for ext in extensions:\n    #define _${ext.name}_number (${ext.number})\n    % endfor\n\n    % for enum in bitmasks:\n      % if enum.bitwidth > 32:\n        <% continue %>\n      % endif\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n    #define ${enum.all_bits_name()} ${hex(enum.all_bits_value())}u\n      % if enum.guard:\n#endif\n      % endif\n    % endfor\n\n    % for enum in bitmasks:\n      % if enum.bitwidth < 64:\n        <% continue %>\n      % endif\n    /* Redefine bitmask values of ${enum.name} */\n      % if enum.guard:\n#ifdef ${enum.guard}\n      % endif\n      % for n, v in enum.name_to_value.items():\n    #define ${n} (${hex(v)}ULL)\n      % endfor\n      % if enum.guard:\n#endif\n      % endif\n    % endfor\n\n    static inline VkFormatFeatureFlags\n    vk_format_features2_to_features(VkFormatFeatureFlags2 features2)\n    {\n       return features2 & VK_ALL_FORMAT_FEATURE_FLAG_BITS;\n    }\n\n    #ifdef __cplusplus\n    } /* extern \"C\" */\n    #endif\n\n    #endif\n    \"\"\"))\n\n\nclass NamedFactory(object):\n    \"\"\"Factory for creating enums.\"\"\"\n\n    def __init__(self, type_):\n        self.registry = {}\n        self.type = type_\n\n    def __call__(self, name, **kwargs):\n        try:\n            return self.registry[name]\n        except KeyError:\n            n = self.registry[name] = self.type(name, **kwargs)\n        return n\n\n    def get(self, name):\n        return self.registry.get(name)\n\n\nclass VkExtension(object):\n    \"\"\"Simple struct-like class representing extensions\"\"\"\n\n    def __init__(self, name, number=None, define=None):\n        self.name = name\n        self.number = number\n        self.define = define\n\n\ndef CamelCase_to_SHOUT_CASE(s):\n   return (s[:1] + re.sub(r'(?<![A-Z])([A-Z])', r'_\\1', s[1:])).upper()\n\ndef compute_max_enum_name(s):\n    if s == \"VkSwapchainImageUsageFlagBitsANDROID\":\n        return \"VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM\"\n    if s == \"VkTensorTilingARM\":\n        return \"VK_TENSOR_TILING_MAX_ENUM_ARM\"\n    max_enum_name = CamelCase_to_SHOUT_CASE(s)\n    last_prefix = max_enum_name.rsplit('_', 1)[-1]\n    # Those special prefixes need to be always at the end\n    if last_prefix in ['AMD', 'AMDX', 'EXT', 'INTEL', 'KHR', 'NV', 'LUNARG', 'QCOM', 'MSFT', 'ARM'] :\n        max_enum_name = \"_\".join(max_enum_name.split('_')[:-1])\n        max_enum_name = max_enum_name + \"_MAX_ENUM_\" + last_prefix\n    else:\n        max_enum_name = max_enum_name + \"_MAX_ENUM\"\n\n    return max_enum_name\n\nclass VkEnum(object):\n    \"\"\"Simple struct-like class representing a single Vulkan Enum.\"\"\"\n\n    def __init__(self, name, bitwidth=32, values=None):\n        self.name = name\n        self.max_enum_name = compute_max_enum_name(name)\n        self.bitwidth = bitwidth\n        self.extension = None\n        # Maps numbers to names\n        self.values = values or dict()\n        self.name_to_value = dict()\n        self.guard = None\n        self.name_to_alias_list = {}\n\n    def all_bits_name(self):\n        assert self.name.startswith('Vk')\n        assert re.search(r'FlagBits[A-Z]*$', self.name)\n\n        return 'VK_ALL_' + CamelCase_to_SHOUT_CASE(self.name[2:])\n\n    def all_bits_value(self):\n        return functools.reduce(lambda a,b: a | b, self.values.keys(), 0)\n\n    def add_value(self, name, value=None,\n                  extnum=None, offset=None, alias=None,\n                  error=False):\n        if alias is not None:\n            assert value is None and offset is None\n            if alias not in self.name_to_value:\n                # We don't have this alias yet.  Just record the alias and\n                # we'll deal with it later.\n                alias_list = self.name_to_alias_list.setdefault(alias, [])\n                alias_list.append(name);\n                return\n\n            # Use the value from the alias\n            value = self.name_to_value[alias]\n\n        assert value is not None or extnum is not None\n        if value is None:\n            value = 1000000000 + (extnum - 1) * 1000 + offset\n            if error:\n                value = -value\n\n        self.name_to_value[name] = value\n        if value not in self.values:\n            self.values[value] = name\n        elif len(self.values[value]) > len(name):\n            self.values[value] = name\n\n        # Now that the value has been fully added, resolve aliases, if any.\n        if name in self.name_to_alias_list:\n            for alias in self.name_to_alias_list[name]:\n                self.add_value(alias, value)\n            del self.name_to_alias_list[name]\n\n    def add_value_from_xml(self, elem, extension=None):\n        self.extension = extension\n        if 'value' in elem.attrib:\n            self.add_value(elem.attrib['name'],\n                           value=int(elem.attrib['value'], base=0))\n        elif 'bitpos' in elem.attrib:\n            self.add_value(elem.attrib['name'],\n                           value=(1 << int(elem.attrib['bitpos'], base=0)))\n        elif 'alias' in elem.attrib:\n            self.add_value(elem.attrib['name'], alias=elem.attrib['alias'])\n        else:\n            error = 'dir' in elem.attrib and elem.attrib['dir'] == '-'\n            if 'extnumber' in elem.attrib:\n                extnum = int(elem.attrib['extnumber'])\n            else:\n                extnum = extension.number\n            self.add_value(elem.attrib['name'],\n                           extnum=extnum,\n                           offset=int(elem.attrib['offset']),\n                           error=error)\n\n    def set_guard(self, g):\n        self.guard = g\n\n\nclass VkChainStruct(object):\n    \"\"\"Simple struct-like class representing a single Vulkan struct identified with a VkStructureType\"\"\"\n    def __init__(self, name, stype):\n        self.name = name\n        self.stype = stype\n        self.extension = None\n\n\ndef struct_get_stype(xml_node):\n    for member in xml_node.findall('./member'):\n        name = member.findall('./name')\n        if len(name) > 0 and name[0].text == \"sType\":\n            return member.get('values')\n    return None\n\nclass VkObjectType(object):\n    \"\"\"Simple struct-like class representing a single Vulkan object type\"\"\"\n    def __init__(self, name):\n        self.name = name\n        self.enum_to_name = dict()\n\n\ndef parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,\n              obj_type_factory, filename, beta):\n    \"\"\"Parse the XML file. Accumulate results into the factories.\n\n    This parser is a memory efficient iterative XML parser that returns a list\n    of VkEnum objects.\n    \"\"\"\n\n    xml = et.parse(filename)\n    api = 'vulkan'\n\n    required_types = get_all_required(xml, 'type', api, beta)\n\n    for enum_type in xml.findall('./enums[@type=\"enum\"]'):\n        if not filter_api(enum_type, api):\n            continue\n\n        type_name = enum_type.attrib['name']\n        if not type_name in required_types:\n            continue\n\n        enum = enum_factory(type_name)\n        for value in enum_type.findall('./enum'):\n            if filter_api(value, api):\n                enum.add_value_from_xml(value)\n\n    # For bitmask we only add the Enum selected for convenience.\n    for enum_type in xml.findall('./enums[@type=\"bitmask\"]'):\n        if not filter_api(enum_type, api):\n            continue\n\n        type_name = enum_type.attrib['name']\n        if not type_name in required_types:\n            continue\n\n        bitwidth = int(enum_type.attrib.get('bitwidth', 32))\n        enum = bitmask_factory(type_name, bitwidth=bitwidth)\n        for value in enum_type.findall('./enum'):\n            if filter_api(value, api):\n                enum.add_value_from_xml(value)\n\n    for feature in xml.findall('./feature'):\n        if not api in feature.attrib['api'].split(','):\n            continue\n\n        for value in feature.findall('./require/enum[@extends]'):\n            extends = value.attrib['extends']\n            enum = enum_factory.get(extends)\n            if enum is not None:\n                enum.add_value_from_xml(value)\n            enum = bitmask_factory.get(extends)\n            if enum is not None:\n                enum.add_value_from_xml(value)\n\n    for struct_type in xml.findall('./types/type[@category=\"struct\"]'):\n        if not filter_api(struct_type, api):\n            continue\n\n        name = struct_type.attrib['name']\n        if name not in required_types:\n            continue\n\n        stype = struct_get_stype(struct_type)\n        if stype is not None:\n            struct_factory(name, stype=stype)\n\n    platform_define = {}\n    for platform in xml.findall('./platforms/platform'):\n        name = platform.attrib['name']\n        define = platform.attrib['protect']\n        platform_define[name] = define\n\n    for ext_elem in xml.findall('./extensions/extension'):\n        ext = Extension.from_xml(ext_elem)\n        if api not in ext.supported:\n            continue\n\n        define = platform_define.get(ext.platform, None)\n        extension = ext_factory(ext.name, number=ext.number, define=define)\n\n        for req_elem in ext_elem.findall('./require'):\n            if not filter_api(req_elem, api):\n                continue\n\n            for value in req_elem.findall('./enum[@extends]'):\n                extends = value.attrib['extends']\n                enum = enum_factory.get(extends)\n                if enum is not None:\n                    enum.add_value_from_xml(value, extension)\n                enum = bitmask_factory.get(extends)\n                if enum is not None:\n                    enum.add_value_from_xml(value, extension)\n\n            for t in req_elem.findall('./type'):\n                struct = struct_factory.get(t.attrib['name'])\n                if struct is not None:\n                    struct.extension = extension\n\n        if define:\n            for value in ext_elem.findall('./require/type[@name]'):\n                enum = enum_factory.get(value.attrib['name'])\n                if enum is not None:\n                    enum.set_guard(define)\n                enum = bitmask_factory.get(value.attrib['name'])\n                if enum is not None:\n                    enum.set_guard(define)\n\n    obj_type_enum = enum_factory.get(\"VkObjectType\")\n    obj_types = obj_type_factory(\"VkObjectType\")\n    for object_type in xml.findall('./types/type[@category=\"handle\"]'):\n        for object_name in object_type.findall('./name'):\n            # Convert to int to avoid undefined enums\n            enum = object_type.attrib['objtypeenum']\n\n            # Annoyingly, object types are hard to filter by API so just\n            # look for whether or not we can find the enum name in the\n            # VkObjectType enum.\n            if enum not in obj_type_enum.name_to_value:\n                continue\n\n            enum_val = obj_type_enum.name_to_value[enum]\n            obj_types.enum_to_name[enum_val] = object_name.text\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--beta', required=True, help='Enable beta extensions.')\n    parser.add_argument('--xml', required=True,\n                        help='Vulkan API XML files',\n                        action='append',\n                        dest='xml_files')\n    parser.add_argument('--out-c',\n                        help='Output C file',\n                        required=True)\n    parser.add_argument('--out-h',\n                        help='Output H file',\n                        required=True)\n    parser.add_argument('--out-d',\n                        help='Output defines H file',\n                        required=True)\n\n    args = parser.parse_args()\n\n    enum_factory = NamedFactory(VkEnum)\n    ext_factory = NamedFactory(VkExtension)\n    struct_factory = NamedFactory(VkChainStruct)\n    obj_type_factory = NamedFactory(VkObjectType)\n    bitmask_factory = NamedFactory(VkEnum)\n\n    for filename in args.xml_files:\n        parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory,\n                  obj_type_factory, filename, args.beta)\n    enums = sorted(enum_factory.registry.values(), key=lambda e: e.name)\n    extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name)\n    structs = sorted(struct_factory.registry.values(), key=lambda e: e.name)\n    bitmasks = sorted(bitmask_factory.registry.values(), key=lambda e: e.name)\n    object_types = sorted(obj_type_factory.registry.values(), key=lambda e: e.name)\n\n    for template, file_ in [(C_TEMPLATE, args.out_c),\n                            (H_TEMPLATE, args.out_h),\n                            (H_DEFINE_TEMPLATE, args.out_d)]:\n        with open(file_, 'w', encoding='utf-8') as f:\n            f.write(template.render(\n                file=os.path.basename(__file__),\n                enums=enums,\n                extensions=extensions,\n                structs=structs,\n                bitmasks=bitmasks,\n                object_types=object_types,\n                copyright=COPYRIGHT))\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "bin/mangohud-setup.sh",
    "content": "#!/usr/bin/env bash\nOS_RELEASE_FILES=(\"/etc/os-release\" \"/usr/lib/os-release\")\nXDG_CONFIG_HOME=\"${XDG_CONFIG_HOME:-$HOME/.config}\"\nMANGOHUD_CONFIG_DIR=\"$XDG_CONFIG_HOME/MangoHud\"\nSU_CMD=$(command -v sudo || command -v doas || echo)\n\n# doas requires a double dash if the command it runs will include any dashes,\n# so append a double dash to the command\n[[ $SU_CMD == *doas ]] && SU_CMD=\"$SU_CMD -- \"\n\n# Correctly identify the os-release file.\nfor os_release in ${OS_RELEASE_FILES[@]} ; do\n    if [[ ! -e \"${os_release}\" ]]; then\n        continue\n    fi\n    DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\\2/p' ${os_release} | sed 's/\"//g')\ndone\n\nmangohud_usage() {\n    echo 'Accepted arguments: \"install\", \"uninstall\".'\n}\n\nmangohud_config() {\n    mkdir -p \"${MANGOHUD_CONFIG_DIR}\"\n    echo You can use the example configuration file from\n    echo /usr/share/doc/mangohud/MangoHud.conf.example\n    echo as a starting point by copying it to\n    echo ${MANGOHUD_CONFIG_DIR}/MangoHud.conf\n    echo\n}\n\nmangohud_uninstall() {\n    [ \"$UID\" -eq 0 ] || exec $SU_CMD bash \"$0\" uninstall\n    rm -rfv \"/usr/lib/mangohud\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.json\"\n    rm -frv \"/usr/share/doc/mangohud\"\n    rm -fv \"/usr/share/man/man1/mangohud.1\"\n    rm -fv \"/usr/bin/mangohud\"\n    rm -fv \"/usr/bin/mangoplot\"\n    rm -fv \"/usr/bin/mangohud.x86\"\n}\n\nmangohud_install() {\n    rm -rf \"$HOME/.local/share/MangoHud/\"\n    rm -f \"$HOME/.local/share/vulkan/implicit_layer.d/\"{mangohud32.json,mangohud64.json}\n\n    [ \"$UID\" -eq 0 ] || mangohud_config\n    [ \"$UID\" -eq 0 ] || tar xf MangoHud-package.tar\n    [ \"$UID\" -eq 0 ] || exec $SU_CMD bash \"$0\" install\n\n    mangohud_uninstall\n\n    DEFAULTLIB=lib32\n    for i in $DISTRO; do\n        case $i in\n            *arch*)\n            DEFAULTLIB=lib64\n            ;;\n        esac\n    done\n\n    echo DEFAULTLIB: $DEFAULTLIB\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/lib/mangohud/lib64/libMangoHud_opengl.so\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/lib/mangohud/lib32/libMangoHud_opengl.so\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_shim.so /usr/lib/mangohud/lib64/libMangoHud_shim.so\n    /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_shim.so /usr/lib/mangohud/lib32/libMangoHud_shim.so\n    /usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json\n    /usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json\n    /usr/bin/install -Dvm644 ./usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1\n    /usr/bin/install -Dvm644 ./usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example\n    /usr/bin/install -vm755  ./usr/bin/mangohud /usr/bin/mangohud\n    /usr/bin/install -vm755  ./usr/bin/mangoplot /usr/bin/mangoplot\n\n    ln -sv $DEFAULTLIB /usr/lib/mangohud/lib\n\n    # FIXME get the triplet somehow\n    ln -sv lib64 /usr/lib/mangohud/x86_64\n    ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu\n    ln -sv . /usr/lib/mangohud/lib64/x86_64\n    ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu\n\n    ln -sv lib32 /usr/lib/mangohud/i686\n    ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu\n    ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu\n\n    mkdir -p /usr/lib/mangohud/tls\n    ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64\n    ln -sv ../lib32 /usr/lib/mangohud/tls/i686\n\n    # Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead\n    if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then\n        ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu\n    fi\n    if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then\n        ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu\n    fi\n    if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then\n        ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu\n    fi\n\n    # $LIB can be \"lib/tls/x86_64\"?\n    ln -sv ../tls /usr/lib/mangohud/lib/tls\n\n    # Let's not clean up because this can be destructive\n    # rm -rf ./usr\n\n    echo \"MangoHud Installed\"\n}\n\nfor a in $@; do\n    case $a in\n        \"install\") mangohud_install;;\n        \"uninstall\") mangohud_uninstall;;\n        *)\n            echo \"Unrecognized command argument: $a\"\n            mangohud_usage\n    esac\ndone\n\nif [ -z $@ ]; then\n    mangohud_usage\nfi\n"
  },
  {
    "path": "bin/mangohud.in",
    "content": "#!/bin/sh\n\nif [ \"$#\" -eq 0 ]; then\n    programname=$(basename \"$0\")\n    echo \"ERROR: No program supplied\"\n    echo\n    echo \"Usage: $programname <program>\"\n    exit 1\nfi\n\n\n# Add exe names newline separated to the string to disable LD_PRELOAD\nDISABLE_LD_PRELOAD=\"\ncs2.sh\nRiseOfTheTombRaider.sh\n\"\n\nMANGOHUD_LIB_NAME=\"@ld_libdir_mangohud@libMangoHud_shim.so\"\n\nif [ \"$1\" = \"--version\" ]; then\n    echo @version@\n    exit 0\nfi\n\nif [ \"$1\" = \"--dlsym\" ]; then\n    # no-op, dlsym enabled by default\n    shift\nfi\n\n# grab all arguments from command_line\ncommand_line=\"$*\"\n# flag for disable_preload\ndisable_preload=false\n\n# Check if the script name or any of the executables in DISABLE_LD_PRELOAD are in the command line\nfor exe in $DISABLE_LD_PRELOAD; do\n    if echo \"$command_line\" | grep -q \"$exe\"; then\n        disable_preload=true\n        break\n    fi\ndone\n\nif [ \"$disable_preload\" = true ]; then\n    exec env MANGOHUD=1 \"$@\"\nelse\n    # Make sure we don't append mangohud lib multiple times\n    # otherwise, this could cause issues with the steam runtime\n    case \":${LD_PRELOAD-}:\" in\n        (*:$MANGOHUD_LIB_NAME:*)\n            ;;\n        (*)\n            # Preload using the plain filenames of the libs, the dynamic linker will\n            # figure out whether the 32 or 64 bit version should be used\n            LD_PRELOAD=\"${LD_PRELOAD:+$LD_PRELOAD:}${MANGOHUD_LIB_NAME}\"\n    esac\n\n    exec env MANGOHUD=1 LD_PRELOAD=\"${LD_PRELOAD}\" \"$@\"\nfi\n"
  },
  {
    "path": "bin/mangoplot.py",
    "content": "#!/usr/bin/env python\n\nr\"\"\"\n    Script to plot all the MangoHud benchmarks contained in a given folder.\n\"\"\"\nfrom pathlib import Path\nimport argparse\nimport csv\n\nfrom typing import List, Union\n\nimport numpy as np\n\nimport matplotlib.pyplot as plt\nfrom matplotlib.widgets import Cursor\nfrom matplotlib.colors import LinearSegmentedColormap\nfrom matplotlib.ticker import EngFormatter\n\nplt.rcParams['font.family'] = \"Lato,serif\"\nplt.rcParams['font.weight'] = \"600\"\n\nbackground_color = \"#1A1C1D\"\nlegend_facecolor = \"#585f63\"\nlegend_textcolor = \"#cccbc9\"\ntext_color = \"#e8e6e3\"\nmango_color = \"#BB770A\"\ngraphbox_linewidth = 1.5\n\nmango_cmap = LinearSegmentedColormap.from_list(\"mango_heat\", [background_color, mango_color])\n\ndef identity(val):\n    r\"\"\"\n        returns the value as-is\n    \"\"\"\n    return val\n\n\ndef get_integer(val: str) -> int:\n    r\"\"\"\n        interprets the str 'val' as an integer and returns it\n    \"\"\"\n    if is_integer(val):\n        return int(val)\n    else:\n        raise ValueError(\"Casting a non integer value: \", val)\n\n\ndef is_integer(s: str) -> bool:\n    r\"\"\"\n        tests if 's' is an integer and returns a bool\n    \"\"\"\n    try:\n        int(s)\n        return True\n    except ValueError:\n        return False\n\n\ndef get_float(val):\n    r\"\"\"\n        interprets the str 'val' as a float and returns it\n    \"\"\"\n    if is_float(val):\n        return float(val)\n    else:\n        return float(\"nan\")\n\n\ndef is_float(s: str) -> bool:\n    r\"\"\"\n        tests if 's' is an float and returns a bool\n    \"\"\"\n    try:\n        float(s)\n        return True\n    except ValueError:\n        return False\n\n\nclass Database:\n    r\"\"\"\n        A class that contains all the csv files within\n        the folder that it is instanced with\n    \"\"\"\n    def __init__(self,\n                 data_folder_path=None,\n                 csv_separator=\" \",\n                 filename_var_separator=\"|\"):\n\n        self.datafiles = []\n        self.result_names_col = None\n        self.result_values_col = None\n        self.sim_settings_names_col = None\n        self.sim_settings_values_col = None\n\n        if data_folder_path:\n            self.load_from_folder(\n                data_folder_path,\n                csv_separator,\n                filename_var_separator)\n\n    def load_from_folder(self,\n                         data_folder_path,\n                         csv_separator=\" \",\n                         filename_var_separator=\"|\"):\n        r\"\"\"\n            Load all CSV files form the given folder\n        \"\"\"\n        filepaths = list(Path(data_folder_path).rglob(\"*.csv\"))\n\n        self.datafiles = []\n        N = len(filepaths)\n\n        print(f\"Loading {N} benchmark files\")\n        for filepath in filepaths:\n            try:\n                datafile = BenchmarkFile(\n                    str(filepath),\n                    csv_separator=csv_separator,\n                    filename_var_separator=filename_var_separator)\n                self.datafiles.append(datafile)\n            except Exception:\n                pass\n\n        self.datafiles.sort()\n\n\nclass BenchmarkFile:\n    r\"\"\"\n        A class that represents a single CSV file, can load CSV files\n        with arbitrary separators. It can return separately any column\n        of the file and any mathematical combinations of its columns.\n    \"\"\"\n\n    def __init__(self,\n                 filepath=\"\",\n                 filename_var_separator=\"|\",\n                 csv_separator=\" \"):\n        self.csv_separator = csv_separator\n        self.filepath = Path(filepath)\n        self.filename = self.filepath.name\n        self.filename_var_separator = filename_var_separator\n        self.variables = dict()\n\n        self.skip_lines = None\n\n        self.columns = []\n        self.column_name_to_index = dict()\n\n        self._is_data_loaded = False\n\n        if not self.filepath.is_file():\n            raise Exception(\"CSV file does not exist\")\n\n        self._read_column_names()\n\n    def __lt__(self, other):\n        stem = self.filename[:-4]  # remove the trailing \".csv\"\n        other_stem = other.filename[:-4]\n        if stem.startswith(other_stem):\n            return False\n        elif stem.startswith(other_stem):\n            return True\n        else:\n            return stem < other_stem\n\n    def set_variable(self, name, value):\n        r\"\"\"\n            Saves a variable within the datafile instance\n            Note: it will not be saved to disk, it's just a helper method to\n                  attach variables to a given data file.\n        \"\"\"\n        self.variables[name] = value\n\n    def get_variable(self, name):\n        r\"\"\"\n            Retrieves a saved variable in the instance\n        \"\"\"\n        return self.variables[name]\n\n    def _read_column_names(self):\n        r\"\"\"\n            Read the first few lines of the benchmark file\n            to look for the row taht contains the benchmark's\n            column names i.e. \"fps\", \"frametime\", \"cpu_load\"... etc\n            and save the columns names and their index\n\n            Note: we decide that we found the right row by looking if it\n                  contains \"fps\"\n                  not the best approach, but it works TM\n        \"\"\"\n\n        with open(self.filepath) as open_file:\n            reader = csv.reader(open_file, delimiter=self.csv_separator)\n\n            found_fps_column = False\n            for row_number, row_content in enumerate(reader):\n                if row_number > 100:\n                    # did not find the row that starts with the\n                    # 'fps' column up until here.  give up.\n                    break\n\n                if \"fps\" in row_content:\n                    self.skip_lines = row_number + 1\n                    found_fps_column = True\n\n                    for col, col_name in enumerate(row_content):\n                        if col_name in self.column_name_to_index:\n                            raise Exception(\"Two columns have the same name\")\n                        self.column_name_to_index[col_name] = col\n\n            if not found_fps_column:\n                raise Exception(\"Not a benchmark file\")\n\n    def _load_data(self):\n        r\"\"\"\n            Load the benchmark data into memory.\n        \"\"\"\n\n        def extend_columns(new_column_num):\n            current_row_num = 0\n            if self.columns:\n                current_row_num = len(self.columns[0])\n                assert (all([len(column) == current_row_num for column in self.columns]))\n\n            current_column_num = len(self.columns)\n            if new_column_num >= current_column_num:\n                self.columns += [[\"\" for j in range(current_row_num)] for i in range(new_column_num - current_column_num)]\n\n        # no need to load data if it's already loaded\n        if self._is_data_loaded:\n            return\n\n        with open(self.filepath) as open_file:\n            reader = csv.reader(open_file, delimiter=self.csv_separator)\n            self._is_data_loaded = True\n\n            for row_number, row_content in enumerate(reader):\n                if row_number <= self.skip_lines:\n                    continue\n\n                extend_columns(len(row_content))\n                for col, val in enumerate(row_content):\n                    self.columns[col].append(val)\n\n        # Delete any eventual empty column\n        if all([val == \"\" for val in self.columns[-1]]):\n            del self.columns[-1]\n\n    def get_column_names(self) -> List[str]:\n        r\"\"\"\n        Returns the list of columns names of the csv file.\n        \"\"\"\n\n        return list(self.column_name_to_index.keys())\n\n    def get(self, col: str, data_type: str = \"float\") \\\n            -> Union[List[float], List[str], List[int], List[complex]]:\n        r\"\"\"\n        Returns the column `col`.\n\n        Parameters\n        ----------\n\n        col : str\n            The desired column name to retrieve, or its index\n\n        data_type : str\n            \"string\", \"integer\" or \"float\", the type to cast\n            the data to before returning it.\n\n        Returns\n        -------\n\n        A list of `data_type` containing the column `col`\n\n        \"\"\"\n\n        if not self._is_data_loaded:\n            self._load_data()\n\n        if len(self.columns) == 0:\n            raise ValueError(\"Datafile empty, can't return any data\")\n\n        data_caster_dict = {\n            \"string\": identity,\n            \"float\": get_float,\n            \"integer\": get_integer\n        }\n\n        if data_type not in data_caster_dict:\n            raise ValueError(\"the given `data_type' doesn't match any \"\n                             \"known types. Which are `string', `integer', \"\n                             \"`float' or `complex'\")\n\n        if is_integer(col):\n            # the column's index is given\n            return [data_caster_dict[data_type](val) for val in self.columns[col]]\n\n        if col in self.column_name_to_index:\n            # a column name has been given\n            return [data_caster_dict[data_type](val)\n                    for val in self.columns[self.column_name_to_index[col]]]\n\n        raise Exception(\"Column {} does not exist\".format(col))\n\n\nif __name__ == '__main__':\n    parser = argparse.ArgumentParser(\n        description='Plot all the MangoHud benchmarks contained in a given folder.')\n\n    parser.add_argument('folder', metavar='folder', nargs=1,\n                        help='path the a MangoHud benchmark folder')\n\n    args = parser.parse_args()\n\n    bench_folder_path = Path(args.folder[0])\n\n    if not bench_folder_path.is_dir():\n        print(f\"The path '{bench_folder_path.absolute()}' \"\n               \"does not point to an existing folder\")\n        exit(1)\n\n    fps_subdivs = 1.0  # one division every fps_subdivs FPS\n\n    y_labels = []  # bench files\n    x_labels = []  # FPS subidivions\n\n    database = Database(bench_folder_path, csv_separator=',')\n    distributions = []\n\n    if len(database.datafiles) == 0:\n        print(f\"The folder \\n   {bench_folder_path.absolute()} \\n\"\n               \"contains no CSV file \"\n               \"(make sure they have the .csv extension)\")\n        exit(1)\n\n    for datafile in database.datafiles:\n        bar_distribution = []\n\n        # sort array to get percentiles\n        fps_array = np.sort(datafile.get(\"fps\"))\n\n        # save percentiles\n        if len(fps_array) < 10000:\n            print(f\"'{datafile.filename}' simulation \"\n                   \"isn't long enough for precise statistics\")\n            datafile.set_variable(\"selected\", False)\n            continue\n\n        # Save label only if this file has long enough simulation\n        y_labels.append(datafile.filename[:-4])\n        datafile.set_variable(\"selected\", True)\n\n        # Save percentiles\n        datafile.set_variable(\"0.1%\", fps_array[int(float(len(fps_array))*0.001)])\n        datafile.set_variable(\"1%\", fps_array[int(float(len(fps_array))*0.01)])\n        datafile.set_variable(\"50%\", fps_array[int(float(len(fps_array))*0.5)])\n\n        datafile.set_variable(\"average fps\", np.average(fps_array))\n\n        for frame_num, fps in enumerate(fps_array):\n            if fps > 1000:\n                print(\"FPS value above 1000, omitting outlier.\")\n                continue\n            index = int(fps/fps_subdivs)\n            for i in range(len(bar_distribution), index+1):\n                bar_distribution.append(0)\n            bar_distribution[index] += 1\n        distributions.append(bar_distribution)\n\n    if not distributions:\n        print(\"Nothing to plot, exiting.\")\n        exit(1)\n\n    num_benchs = len(distributions)\n    max_size = 0\n    for distrib in distributions:\n        max_size = max(max_size, len(distrib))\n    for distrib in distributions:\n        for i in range(len(distrib), max_size):\n            distrib.append(0)\n\n    for i in range(max_size):\n        x_labels.append(str(fps_subdivs * i))\n\n    fig, ax = plt.subplots()\n\n    # change color of the graph box to the same color as the text\n    for spine in ['left', 'right', 'bottom', 'top']:\n      ax.spines[spine].set_color(text_color)\n      ax.spines[spine].set_linewidth(graphbox_linewidth)\n\n    im = ax.imshow(distributions,\n                   aspect=\"auto\",\n                   extent=[0, max_size*fps_subdivs, 0, num_benchs],\n                   cmap=mango_cmap)\n\n    # draw thick line that separates each benchmark\n    for i in range(len(y_labels)+1):\n        ax.axhline(float(i), color=text_color, lw=graphbox_linewidth)\n\n    i = 0\n    for datafile in database.datafiles:\n        if datafile.get_variable(\"selected\"):\n            kwargs = dict(ymin=(num_benchs-i-1+0.15)/num_benchs,\n                          ymax=(num_benchs-i-0.15)/num_benchs,\n                          lw=3)\n\n            ax.axvline(datafile.get_variable(\"0.1%\"),\n                       color='#35260f',\n                       label=(\"0.1%\" if i == 0 else None), **kwargs)\n\n            ax.axvline(datafile.get_variable(\"1%\"),\n                       color='#6E4503',\n                       label=(\"1%\" if i == 0 else None), **kwargs)\n\n            ax.axvline(datafile.get_variable(\"50%\"),\n                       color='#0967BA',\n                       label=(\"50%\" if i == 0 else None), **kwargs)\n\n            ax.axvline(datafile.get_variable(\"average fps\"),\n                       color='#003A6E',\n                       label=(\"Average\" if i == 0 else None), **kwargs)\n            i += 1\n\n    ax.tick_params(axis='y', colors=text_color)\n    ax.tick_params(axis='x', colors=text_color)\n    ax.set_yticks(np.arange(len(y_labels)-0.5, 0, -1), labels=y_labels)\n    ax.grid(False)\n\n    fig.set_facecolor(background_color)\n\n    ax.ticklabel_format(axis='x', style='plain')\n\n    formatter0 = EngFormatter(unit='FPS')\n    ax.xaxis.set_major_formatter(formatter0)\n\n    plt.tight_layout()\n    plt.legend(facecolor=legend_facecolor, labelcolor=legend_textcolor)\n\n    cursor = Cursor(ax,\n                    horizOn=False,\n                    color='#6c49abff',\n                    linewidth=4,\n                    useblit=True)\n\n    plt.show()\n"
  },
  {
    "path": "bin/meson.build",
    "content": "# runtime dependencies for `mangoplot`: matplotlib and a GUI backed like PyQt5\ninstall_data(\n  'mangoplot.py',\n  install_dir: get_option('bindir'),\n  rename: 'mangoplot',\n  install_mode: 'rwxr-xr-x'\n)\n"
  },
  {
    "path": "bin/vk_dispatch_table_gen.py",
    "content": "COPYRIGHT = \"\"\"\\\n/*\n * Copyright 2020 Intel Corporation\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * 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, sub license, 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 (including the\n * next paragraph) shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n * ANY 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\"\"\"\n\nimport argparse\nimport math\nimport os\n\nfrom mako.template import Template\n\n# Mesa-local imports must be declared in meson variable\n# '{file_without_suffix}_depend_files'.\nfrom vk_entrypoints import get_entrypoints_from_xml\n\n# We generate a static hash table for entry point lookup\n# (vkGetProcAddress). We use a linear congruential generator for our hash\n# function and a power-of-two size table. The prime numbers are determined\n# experimentally.\n\nTEMPLATE_H = Template(COPYRIGHT + \"\"\"\\\n/* This file generated from ${filename}, don't edit directly. */\n\n#ifndef VK_DISPATCH_TABLE_H\n#define VK_DISPATCH_TABLE_H\n\n#include \"vulkan/vulkan.h\"\n\n#include \"vk_extensions.h\"\n\n/* Windows api conflict */\n#ifdef _WIN32\n#include <windows.h>\n#ifdef CreateSemaphore\n#undef CreateSemaphore\n#endif\n#ifdef CreateEvent\n#undef CreateEvent\n#endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef _MSC_VER\nVKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void);\n#endif\n\n<%def name=\"dispatch_table(entrypoints)\">\n% for e in entrypoints:\n  % if e.alias:\n    <% continue %>\n  % endif\n  % if e.guard is not None:\n#ifdef ${e.guard}\n  % endif\n  % if e.aliases:\n    union {\n        PFN_vk${e.name} ${e.name};\n      % for a in e.aliases:\n        PFN_vk${a.name} ${a.name};\n      % endfor\n    };\n  % else:\n    PFN_vk${e.name} ${e.name};\n  % endif\n  % if e.guard is not None:\n#else\n    % if e.aliases:\n    union {\n        PFN_vkVoidFunction ${e.name};\n      % for a in e.aliases:\n        PFN_vkVoidFunction ${a.name};\n      % endfor\n    };\n    % else:\n    PFN_vkVoidFunction ${e.name};\n    % endif\n#endif\n  % endif\n% endfor\n</%def>\n\n<%def name=\"entrypoint_table(type, entrypoints)\">\nstruct vk_${type}_entrypoint_table {\n% for e in entrypoints:\n  % if e.guard is not None:\n#ifdef ${e.guard}\n  % endif\n    PFN_vk${e.name} ${e.name};\n  % if e.guard is not None:\n#else\n    PFN_vkVoidFunction ${e.name};\n# endif\n  % endif\n% endfor\n};\n</%def>\n\nstruct vk_instance_dispatch_table {\n  ${dispatch_table(instance_entrypoints)}\n};\n\nstruct vk_physical_device_dispatch_table {\n  ${dispatch_table(physical_device_entrypoints)}\n};\n\nstruct vk_device_dispatch_table {\n  ${dispatch_table(device_entrypoints)}\n};\n\nstruct vk_dispatch_table {\n    union {\n        struct {\n            struct vk_instance_dispatch_table instance;\n            struct vk_physical_device_dispatch_table physical_device;\n            struct vk_device_dispatch_table device;\n        };\n\n        struct {\n            ${dispatch_table(instance_entrypoints)}\n            ${dispatch_table(physical_device_entrypoints)}\n            ${dispatch_table(device_entrypoints)}\n        };\n    };\n};\n\n${entrypoint_table('instance', instance_entrypoints)}\n${entrypoint_table('physical_device', physical_device_entrypoints)}\n${entrypoint_table('device', device_entrypoints)}\n\n<%def name=\"uncompacted_dispatch_table(entrypoints)\">\n% for e in entrypoints:\n  % if e.alias:\n    <% continue %>\n  % endif\n  % if e.guard is not None:\n#ifdef ${e.guard}\n  % endif\n    PFN_vk${e.name} ${e.name};\n  % if e.aliases:\n    % for a in e.aliases:\n    PFN_vk${a.name} ${a.name};\n    % endfor\n  % endif\n  % if e.guard is not None:\n#else\n    PFN_vkVoidFunction ${e.name};\n    % if e.aliases:\n      % for a in e.aliases:\n        PFN_vkVoidFunction ${a.name};\n      % endfor\n    % endif\n#endif\n  % endif\n% endfor\n</%def>\n\n\nstruct vk_instance_uncompacted_dispatch_table {\n  ${uncompacted_dispatch_table(instance_entrypoints)}\n};\n\nstruct vk_physical_device_uncompacted_dispatch_table {\n  ${uncompacted_dispatch_table(physical_device_entrypoints)}\n};\n\nstruct vk_device_uncompacted_dispatch_table {\n  ${uncompacted_dispatch_table(device_entrypoints)}\n};\n\nstruct vk_uncompacted_dispatch_table {\n    union {\n        struct {\n            struct vk_instance_uncompacted_dispatch_table instance;\n            struct vk_physical_device_uncompacted_dispatch_table physical_device;\n            struct vk_device_uncompacted_dispatch_table device;\n        };\n\n        struct {\n            ${uncompacted_dispatch_table(instance_entrypoints)}\n            ${uncompacted_dispatch_table(physical_device_entrypoints)}\n            ${uncompacted_dispatch_table(device_entrypoints)}\n        };\n    };\n};\n\nvoid\nvk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table,\n                                PFN_vkGetInstanceProcAddr gpa,\n                                VkInstance instance);\nvoid\nvk_physical_device_dispatch_table_load(struct vk_physical_device_dispatch_table *table,\n                                       PFN_vkGetInstanceProcAddr gpa,\n                                       VkInstance instance);\nvoid\nvk_device_dispatch_table_load(struct vk_device_dispatch_table *table,\n                              PFN_vkGetDeviceProcAddr gpa,\n                              VkDevice device);\n\nvoid\nvk_instance_uncompacted_dispatch_table_load(struct vk_instance_uncompacted_dispatch_table *table,\n                                PFN_vkGetInstanceProcAddr gpa,\n                                VkInstance instance);\nvoid\nvk_physical_device_uncompacted_dispatch_table_load(struct vk_physical_device_uncompacted_dispatch_table *table,\n                                       PFN_vkGetInstanceProcAddr gpa,\n                                       VkInstance instance);\nvoid\nvk_device_uncompacted_dispatch_table_load(struct vk_device_uncompacted_dispatch_table *table,\n                              PFN_vkGetDeviceProcAddr gpa,\n                              VkDevice device);\n\nvoid vk_instance_dispatch_table_from_entrypoints(\n    struct vk_instance_dispatch_table *dispatch_table,\n    const struct vk_instance_entrypoint_table *entrypoint_table,\n    bool overwrite);\n\nvoid vk_physical_device_dispatch_table_from_entrypoints(\n    struct vk_physical_device_dispatch_table *dispatch_table,\n    const struct vk_physical_device_entrypoint_table *entrypoint_table,\n    bool overwrite);\n\nvoid vk_device_dispatch_table_from_entrypoints(\n    struct vk_device_dispatch_table *dispatch_table,\n    const struct vk_device_entrypoint_table *entrypoint_table,\n    bool overwrite);\n\nPFN_vkVoidFunction\nvk_instance_dispatch_table_get(const struct vk_instance_dispatch_table *table,\n                               const char *name);\n\nPFN_vkVoidFunction\nvk_physical_device_dispatch_table_get(const struct vk_physical_device_dispatch_table *table,\n                                      const char *name);\n\nPFN_vkVoidFunction\nvk_device_dispatch_table_get(const struct vk_device_dispatch_table *table,\n                             const char *name);\n\nPFN_vkVoidFunction\nvk_instance_dispatch_table_get_if_supported(\n    const struct vk_instance_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts);\n\nPFN_vkVoidFunction\nvk_physical_device_dispatch_table_get_if_supported(\n    const struct vk_physical_device_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts);\n\nPFN_vkVoidFunction\nvk_device_dispatch_table_get_if_supported(\n    const struct vk_device_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts,\n    const struct vk_device_extension_table *device_exts);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* VK_DISPATCH_TABLE_H */\n\"\"\")\n\nTEMPLATE_C = Template(COPYRIGHT + \"\"\"\\\n/* This file generated from ${filename}, don't edit directly. */\n\n#include \"vk_dispatch_table.h\"\n\n#include \"../src/mesa/util/macros.h\"\n#include \"string.h\"\n\n<%def name=\"load_dispatch_table(type, VkType, ProcAddr, entrypoints)\">\nvoid\nvk_${type}_dispatch_table_load(struct vk_${type}_dispatch_table *table,\n                               PFN_vk${ProcAddr} gpa,\n                               ${VkType} obj)\n{\n% if type != 'physical_device':\n    table->${ProcAddr} = gpa;\n% endif\n% for e in entrypoints:\n  % if e.alias or e.name == '${ProcAddr}':\n    <% continue %>\n  % endif\n  % if e.guard is not None:\n#ifdef ${e.guard}\n  % endif\n    table->${e.name} = (PFN_vk${e.name}) gpa(obj, \"vk${e.name}\");\n  % for a in e.aliases:\n    if (table->${e.name} == NULL) {\n        table->${e.name} = (PFN_vk${e.name}) gpa(obj, \"vk${a.name}\");\n    }\n  % endfor\n  % if e.guard is not None:\n#endif\n  % endif\n% endfor\n}\n</%def>\n\n${load_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr',\n                      instance_entrypoints)}\n\n${load_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr',\n                      physical_device_entrypoints)}\n\n${load_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr',\n                      device_entrypoints)}\n\n<%def name=\"load_uncompacted_dispatch_table(type, VkType, ProcAddr, entrypoints)\">\nvoid\nvk_${type}_uncompacted_dispatch_table_load(struct vk_${type}_uncompacted_dispatch_table *table,\n                               PFN_vk${ProcAddr} gpa,\n                               ${VkType} obj)\n{\n% if type != 'physical_device':\n    table->${ProcAddr} = gpa;\n% endif\n% for e in entrypoints:\n  % if e.alias or e.name == '${ProcAddr}':\n    <% continue %>\n  % endif\n  % if e.guard is not None:\n#ifdef ${e.guard}\n  % endif\n    table->${e.name} = (PFN_vk${e.name}) gpa(obj, \"vk${e.name}\");\n  % for a in e.aliases:\n    table->${a.name} = (PFN_vk${a.name}) gpa(obj, \"vk${a.name}\");\n    if (table->${e.name} && !table->${a.name})\n       table->${a.name} = (PFN_vk${a.name}) table->${e.name};\n    if (!table->${e.name})\n       table->${e.name} = (PFN_vk${e.name}) table->${a.name};\n  % endfor\n  % if e.guard is not None:\n#endif\n  % endif\n% endfor\n}\n</%def>\n\n${load_uncompacted_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr',\n                      instance_entrypoints)}\n\n${load_uncompacted_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr',\n                      physical_device_entrypoints)}\n\n${load_uncompacted_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr',\n                      device_entrypoints)}\n\n\nstruct string_map_entry {\n   uint32_t name;\n   uint32_t hash;\n   uint32_t num;\n};\n\n/* We use a big string constant to avoid lots of reloctions from the entry\n * point table to lots of little strings. The entries in the entry point table\n * store the index into this big string.\n */\n\n<%def name=\"strmap(strmap, prefix)\">\nstatic const char ${prefix}_strings[] =\n% for s in strmap.sorted_strings:\n    \"${s.string}\\\\0\"\n% endfor\n;\n\nstatic const struct string_map_entry ${prefix}_string_map_entries[] = {\n% for s in strmap.sorted_strings:\n    { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */\n% endfor\n};\n\n/* Hash table stats:\n * size ${len(strmap.sorted_strings)} entries\n * collisions entries:\n% for i in range(10):\n *     ${i}${'+' if i == 9 else ' '}     ${strmap.collisions[i]}\n% endfor\n */\n\n#define none 0xffff\nstatic const uint16_t ${prefix}_string_map[${strmap.hash_size}] = {\n% for e in strmap.mapping:\n    ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' },\n% endfor\n};\n\nstatic int\n${prefix}_string_map_lookup(const char *str)\n{\n    static const uint32_t prime_factor = ${strmap.prime_factor};\n    static const uint32_t prime_step = ${strmap.prime_step};\n    const struct string_map_entry *e;\n    uint32_t hash, h;\n    uint16_t i;\n    const char *p;\n\n    hash = 0;\n    for (p = str; *p; p++)\n        hash = hash * prime_factor + *p;\n\n    h = hash;\n    while (1) {\n        i = ${prefix}_string_map[h & ${strmap.hash_mask}];\n        if (i == none)\n           return -1;\n        e = &${prefix}_string_map_entries[i];\n        if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0)\n            return e->num;\n        h += prime_step;\n    }\n\n    return -1;\n}\n</%def>\n\n${strmap(instance_strmap, 'instance')}\n${strmap(physical_device_strmap, 'physical_device')}\n${strmap(device_strmap, 'device')}\n\n<% assert len(instance_entrypoints) < 2**8 %>\nstatic const uint8_t instance_compaction_table[] = {\n% for e in instance_entrypoints:\n    ${e.disp_table_index},\n% endfor\n};\n\n<% assert len(physical_device_entrypoints) < 2**8 %>\nstatic const uint8_t physical_device_compaction_table[] = {\n% for e in physical_device_entrypoints:\n    ${e.disp_table_index},\n% endfor\n};\n\n<% assert len(device_entrypoints) < 2**16 %>\nstatic const uint16_t device_compaction_table[] = {\n% for e in device_entrypoints:\n    ${e.disp_table_index},\n% endfor\n};\n\nstatic bool\nvk_instance_entrypoint_is_enabled(int index, uint32_t core_version,\n                                  const struct vk_instance_extension_table *instance)\n{\n   switch (index) {\n% for e in instance_entrypoints:\n   case ${e.entry_table_index}:\n      /* ${e.name} */\n   % if e.core_version:\n      return ${e.core_version.c_vk_version()} <= core_version;\n   % elif e.extensions:\n     % for ext in e.extensions:\n        % if ext.type == 'instance':\n      if (instance->${ext.name[3:]}) return true;\n        % else:\n      /* All device extensions are considered enabled at the instance level */\n      return true;\n        % endif\n     % endfor\n      return false;\n   % else:\n      return true;\n   % endif\n% endfor\n   default:\n      return false;\n   }\n}\n\n/** Return true if the core version or extension in which the given entrypoint\n * is defined is enabled.\n *\n * If device is NULL, all device extensions are considered enabled.\n */\nstatic bool\nvk_physical_device_entrypoint_is_enabled(int index, uint32_t core_version,\n                                         const struct vk_instance_extension_table *instance)\n{\n   switch (index) {\n% for e in physical_device_entrypoints:\n   case ${e.entry_table_index}:\n      /* ${e.name} */\n   % if e.core_version:\n      return ${e.core_version.c_vk_version()} <= core_version;\n   % elif e.extensions:\n     % for ext in e.extensions:\n        % if ext.type == 'instance':\n      if (instance->${ext.name[3:]}) return true;\n        % else:\n      /* All device extensions are considered enabled at the instance level */\n      return true;\n        % endif\n     % endfor\n      return false;\n   % else:\n      return true;\n   % endif\n% endfor\n   default:\n      return false;\n   }\n}\n\n/** Return true if the core version or extension in which the given entrypoint\n * is defined is enabled.\n *\n * If device is NULL, all device extensions are considered enabled.\n */\nstatic bool\nvk_device_entrypoint_is_enabled(int index, uint32_t core_version,\n                                const struct vk_instance_extension_table *instance,\n                                const struct vk_device_extension_table *device)\n{\n   switch (index) {\n% for e in device_entrypoints:\n   case ${e.entry_table_index}:\n      /* ${e.name} */\n   % if e.core_version:\n      return ${e.core_version.c_vk_version()} <= core_version;\n   % elif e.extensions:\n     % for ext in e.extensions:\n        % if ext.type == 'instance':\n      if (instance->${ext.name[3:]}) return true;\n        % else:\n      if (!device || device->${ext.name[3:]}) return true;\n        % endif\n     % endfor\n      return false;\n   % else:\n      return true;\n   % endif\n% endfor\n   default:\n      return false;\n   }\n}\n\n#ifdef _MSC_VER\nVKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void)\n{\n   UNREACHABLE(\"Entrypoint not implemented\");\n}\n\nstatic const void *get_function_target(const void *func)\n{\n   const uint8_t *address = func;\n#ifdef _M_X64\n   /* Incremental linking may indirect through relative jump */\n   if (*address == 0xE9)\n   {\n      /* Compute JMP target if the first byte is opcode 0xE9 */\n      uint32_t offset;\n      memcpy(&offset, address + 1, 4);\n      address += offset + 5;\n   }\n#else\n   /* Add other platforms here if necessary */\n#endif\n   return address;\n}\n\nstatic bool vk_function_is_stub(PFN_vkVoidFunction func)\n{\n   return (func == vk_entrypoint_stub) || (get_function_target(func) == get_function_target(vk_entrypoint_stub));\n}\n#endif\n\n<%def name=\"dispatch_table_from_entrypoints(type)\">\nvoid vk_${type}_dispatch_table_from_entrypoints(\n    struct vk_${type}_dispatch_table *dispatch_table,\n    const struct vk_${type}_entrypoint_table *entrypoint_table,\n    bool overwrite)\n{\n    PFN_vkVoidFunction *disp = (PFN_vkVoidFunction *)dispatch_table;\n    PFN_vkVoidFunction *entry = (PFN_vkVoidFunction *)entrypoint_table;\n\n    if (overwrite) {\n        memset(dispatch_table, 0, sizeof(*dispatch_table));\n        for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) {\n#ifdef _MSC_VER\n            assert(entry[i] != NULL);\n            if (vk_function_is_stub(entry[i]))\n#else\n            if (entry[i] == NULL)\n#endif\n                continue;\n            unsigned disp_index = ${type}_compaction_table[i];\n            assert(disp[disp_index] == NULL);\n            disp[disp_index] = entry[i];\n        }\n    } else {\n        for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) {\n            unsigned disp_index = ${type}_compaction_table[i];\n#ifdef _MSC_VER\n            assert(entry[i] != NULL);\n            if (disp[disp_index] == NULL && !vk_function_is_stub(entry[i]))\n#else\n            if (disp[disp_index] == NULL)\n#endif\n                disp[disp_index] = entry[i];\n        }\n    }\n}\n</%def>\n\n${dispatch_table_from_entrypoints('instance')}\n${dispatch_table_from_entrypoints('physical_device')}\n${dispatch_table_from_entrypoints('device')}\n\n<%def name=\"lookup_funcs(type)\">\nstatic PFN_vkVoidFunction\nvk_${type}_dispatch_table_get_for_entry_index(\n    const struct vk_${type}_dispatch_table *table, int entry_index)\n{\n    assert(entry_index >= 0);\n    assert((size_t)entry_index < ARRAY_SIZE(${type}_compaction_table));\n    int disp_index = ${type}_compaction_table[entry_index];\n    return ((PFN_vkVoidFunction *)table)[disp_index];\n}\n\nPFN_vkVoidFunction\nvk_${type}_dispatch_table_get(\n    const struct vk_${type}_dispatch_table *table, const char *name)\n{\n    int entry_index = ${type}_string_map_lookup(name);\n    if (entry_index < 0)\n        return NULL;\n\n    return vk_${type}_dispatch_table_get_for_entry_index(table, entry_index);\n}\n</%def>\n\n${lookup_funcs('instance')}\n${lookup_funcs('physical_device')}\n${lookup_funcs('device')}\n\nPFN_vkVoidFunction\nvk_instance_dispatch_table_get_if_supported(\n    const struct vk_instance_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts)\n{\n    int entry_index = instance_string_map_lookup(name);\n    if (entry_index < 0)\n        return NULL;\n\n    if (!vk_instance_entrypoint_is_enabled(entry_index, core_version,\n                                           instance_exts))\n        return NULL;\n\n    return vk_instance_dispatch_table_get_for_entry_index(table, entry_index);\n}\n\nPFN_vkVoidFunction\nvk_physical_device_dispatch_table_get_if_supported(\n    const struct vk_physical_device_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts)\n{\n    int entry_index = physical_device_string_map_lookup(name);\n    if (entry_index < 0)\n        return NULL;\n\n    if (!vk_physical_device_entrypoint_is_enabled(entry_index, core_version,\n                                                  instance_exts))\n        return NULL;\n\n    return vk_physical_device_dispatch_table_get_for_entry_index(table, entry_index);\n}\n\nPFN_vkVoidFunction\nvk_device_dispatch_table_get_if_supported(\n    const struct vk_device_dispatch_table *table,\n    const char *name,\n    uint32_t core_version,\n    const struct vk_instance_extension_table *instance_exts,\n    const struct vk_device_extension_table *device_exts)\n{\n    int entry_index = device_string_map_lookup(name);\n    if (entry_index < 0)\n        return NULL;\n\n    if (!vk_device_entrypoint_is_enabled(entry_index, core_version,\n                                         instance_exts, device_exts))\n        return NULL;\n\n    return vk_device_dispatch_table_get_for_entry_index(table, entry_index);\n}\n\"\"\")\n\nU32_MASK = 2**32 - 1\n\nPRIME_FACTOR = 5024183\nPRIME_STEP = 19\n\nclass StringIntMapEntry:\n    def __init__(self, string, num):\n        self.string = string\n        self.num = num\n\n        # Calculate the same hash value that we will calculate in C.\n        h = 0\n        for c in string:\n            h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK\n        self.hash = h\n\n        self.offset = None\n\ndef round_to_pow2(x):\n    return 2**int(math.ceil(math.log(x, 2)))\n\nclass StringIntMap:\n    def __init__(self):\n        self.baked = False\n        self.strings = {}\n\n    def add_string(self, string, num):\n        assert not self.baked\n        assert string not in self.strings\n        assert 0 <= num < 2**31\n        self.strings[string] = StringIntMapEntry(string, num)\n\n    def bake(self):\n        self.sorted_strings = \\\n            sorted(self.strings.values(), key=lambda x: x.string)\n        offset = 0\n        for entry in self.sorted_strings:\n            entry.offset = offset\n            offset += len(entry.string) + 1\n\n        # Save off some values that we'll need in C\n        self.hash_size = round_to_pow2(len(self.strings) * 1.25)\n        self.hash_mask = self.hash_size - 1\n        self.prime_factor = PRIME_FACTOR\n        self.prime_step = PRIME_STEP\n\n        self.mapping = [-1] * self.hash_size\n        self.collisions = [0] * 10\n        for idx, s in enumerate(self.sorted_strings):\n            level = 0\n            h = s.hash\n            while self.mapping[h & self.hash_mask] >= 0:\n                h = h + PRIME_STEP\n                level = level + 1\n            self.collisions[min(level, 9)] += 1\n            self.mapping[h & self.hash_mask] = idx\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--out-c', help='Output C file.')\n    parser.add_argument('--out-h', help='Output H file.')\n    parser.add_argument('--beta', required=True, help='Enable beta extensions.')\n    parser.add_argument('--xml',\n                        help='Vulkan API XML file.',\n                        required=True,\n                        action='append',\n                        dest='xml_files')\n    args = parser.parse_args()\n\n    entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta)\n\n    device_entrypoints = []\n    physical_device_entrypoints = []\n    instance_entrypoints = []\n    for e in entrypoints:\n        if e.is_device_entrypoint():\n            device_entrypoints.append(e)\n        elif e.is_physical_device_entrypoint():\n            physical_device_entrypoints.append(e)\n        else:\n            instance_entrypoints.append(e)\n\n    for i, e in enumerate(e for e in device_entrypoints if not e.alias):\n        e.disp_table_index = i\n\n    device_strmap = StringIntMap()\n    for i, e in enumerate(device_entrypoints):\n        e.entry_table_index = i\n        device_strmap.add_string(\"vk\" + e.name, e.entry_table_index)\n    device_strmap.bake()\n\n    for i, e in enumerate(e for e in physical_device_entrypoints if not e.alias):\n        e.disp_table_index = i\n\n    physical_device_strmap = StringIntMap()\n    for i, e in enumerate(physical_device_entrypoints):\n        e.entry_table_index = i\n        physical_device_strmap.add_string(\"vk\" + e.name, e.entry_table_index)\n    physical_device_strmap.bake()\n\n    for i, e in enumerate(e for e in instance_entrypoints if not e.alias):\n        e.disp_table_index = i\n\n    instance_strmap = StringIntMap()\n    for i, e in enumerate(instance_entrypoints):\n        e.entry_table_index = i\n        instance_strmap.add_string(\"vk\" + e.name, e.entry_table_index)\n    instance_strmap.bake()\n\n    # For outputting entrypoints.h we generate a anv_EntryPoint() prototype\n    # per entry point.\n    try:\n        if args.out_h:\n            with open(args.out_h, 'w', encoding='utf-8') as f:\n                f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints,\n                                          physical_device_entrypoints=physical_device_entrypoints,\n                                          device_entrypoints=device_entrypoints,\n                                          filename=os.path.basename(__file__)))\n        if args.out_c:\n            with open(args.out_c, 'w', encoding='utf-8') as f:\n                f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints,\n                                          physical_device_entrypoints=physical_device_entrypoints,\n                                          device_entrypoints=device_entrypoints,\n                                          instance_strmap=instance_strmap,\n                                          physical_device_strmap=physical_device_strmap,\n                                          device_strmap=device_strmap,\n                                          filename=os.path.basename(__file__)))\n    except Exception:\n        # In the event there's an error, this imports some helpers from mako\n        # to print a useful stack trace and prints it, then exits with\n        # status 1, if python is run with debug; otherwise it just raises\n        # the exception\n        import sys\n        from mako import exceptions\n        print(exceptions.text_error_template().render(), file=sys.stderr)\n        sys.exit(1)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "bin/vk_entrypoints.py",
    "content": "# Copyright 2020 Intel Corporation\n#\n# Permission is hereby granted, free of charge, to any person obtaining a\n# 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, sub license, 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 (including the\n# next paragraph) shall be included in all copies or substantial portions\n# of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n# ANY 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\nimport xml.etree.ElementTree as et\n\nfrom collections import OrderedDict, namedtuple\n\n# Mesa-local imports must be declared in meson variable\n# '{file_without_suffix}_depend_files'.\nfrom vk_extensions import get_all_required, filter_api\n\nEntrypointParam = namedtuple('EntrypointParam', 'type name decl len')\n\nclass EntrypointBase:\n    def __init__(self, name):\n        assert name.startswith('vk')\n        self.name = name[2:]\n        self.alias = None\n        self.guard = None\n        self.entry_table_index = None\n        # Extensions which require this entrypoint\n        self.core_version = None\n        self.extensions = []\n\n    def prefixed_name(self, prefix):\n        return prefix + '_' + self.name\n\nclass Entrypoint(EntrypointBase):\n    def __init__(self, name, return_type, params):\n        super(Entrypoint, self).__init__(name)\n        self.return_type = return_type\n        self.params = params\n        self.guard = None\n        self.aliases = []\n        self.disp_table_index = None\n\n    def is_physical_device_entrypoint(self):\n        return self.params[0].type in ('VkPhysicalDevice', )\n\n    def is_device_entrypoint(self):\n        return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue')\n\n    def decl_params(self, start=0):\n        return ', '.join(p.decl for p in self.params[start:])\n\n    def call_params(self, start=0):\n        return ', '.join(p.name for p in self.params[start:])\n\nclass EntrypointAlias(EntrypointBase):\n    def __init__(self, name, entrypoint):\n        super(EntrypointAlias, self).__init__(name)\n        self.alias = entrypoint\n        entrypoint.aliases.append(self)\n\n    def is_physical_device_entrypoint(self):\n        return self.alias.is_physical_device_entrypoint()\n\n    def is_device_entrypoint(self):\n        return self.alias.is_device_entrypoint()\n\n    def prefixed_name(self, prefix):\n        return self.alias.prefixed_name(prefix)\n\n    @property\n    def params(self):\n        return self.alias.params\n\n    @property\n    def return_type(self):\n        return self.alias.return_type\n\n    @property\n    def disp_table_index(self):\n        return self.alias.disp_table_index\n\n    def decl_params(self):\n        return self.alias.decl_params()\n\n    def call_params(self):\n        return self.alias.call_params()\n\ndef get_entrypoints(doc, api, beta):\n    \"\"\"Extract the entry points from the registry.\"\"\"\n    entrypoints = OrderedDict()\n\n    required = get_all_required(doc, 'command', api, beta)\n\n    for command in doc.findall('./commands/command'):\n        if not filter_api(command, api):\n            continue\n\n        if 'alias' in command.attrib:\n            name = command.attrib['name']\n            target = command.attrib['alias']\n            e = EntrypointAlias(name, entrypoints[target])\n        else:\n            name = command.find('./proto/name').text\n            ret_type = command.find('./proto/type').text\n            params = [EntrypointParam(\n                type=p.find('./type').text,\n                name=p.find('./name').text,\n                decl=''.join(p.itertext()),\n                len=p.attrib.get('altlen', p.attrib.get('len', None))\n            ) for p in command.findall('./param') if filter_api(p, api)]\n            # They really need to be unique\n            e = Entrypoint(name, ret_type, params)\n\n        if name not in required:\n            continue\n\n        r = required[name]\n        e.core_version = r.core_version\n        e.extensions = r.extensions\n        e.guard = r.guard\n\n        assert name not in entrypoints, name\n        entrypoints[name] = e\n\n    return entrypoints.values()\n\ndef get_entrypoints_from_xml(xml_files, beta, api='vulkan'):\n    entrypoints = []\n\n    for filename in xml_files:\n        doc = et.parse(filename)\n        entrypoints += get_entrypoints(doc, api, beta)\n\n    return entrypoints\n"
  },
  {
    "path": "bin/vk_extensions.py",
    "content": "import copy\nimport re\nimport xml.etree.ElementTree as et\n\ndef get_api_list(s):\n    apis = []\n    for a in s.split(','):\n        if a == 'disabled':\n            continue\n        assert a in ('vulkan', 'vulkansc')\n        apis.append(a)\n    return apis\n\nclass Extension:\n    def __init__(self, name, number, ext_version):\n        self.name = name\n        self.type = None\n        self.number = number\n        self.platform = None\n        self.provisional = False\n        self.ext_version = int(ext_version)\n        self.supported = []\n\n    def from_xml(ext_elem):\n        name = ext_elem.attrib['name']\n        number = int(ext_elem.attrib['number'])\n        supported = get_api_list(ext_elem.attrib['supported'])\n        if name == 'VK_ANDROID_native_buffer':\n            assert not supported\n            supported = ['vulkan']\n\n        if not supported:\n            return Extension(name, number, 0)\n\n        version = None\n        for enum_elem in ext_elem.findall('.require/enum'):\n            if enum_elem.attrib['name'].endswith('_SPEC_VERSION'):\n                # Skip alias SPEC_VERSIONs\n                if 'value' in enum_elem.attrib:\n                    assert version is None\n                    version = int(enum_elem.attrib['value'])\n\n        assert version is not None\n        ext = Extension(name, number, version)\n        ext.type = ext_elem.attrib['type']\n        ext.platform = ext_elem.attrib.get('platform', None)\n        ext.provisional = ext_elem.attrib.get('provisional', False)\n        ext.supported = supported\n\n        return ext\n\n    def c_android_condition(self):\n        # if it's an EXT or vendor extension, it's allowed\n        if not self.name.startswith(ANDROID_EXTENSION_WHITELIST_PREFIXES):\n            return 'true'\n\n        allowed_version = ALLOWED_ANDROID_VERSION.get(self.name, None)\n        if allowed_version is None:\n            return 'false'\n\n        return 'ANDROID_API_LEVEL >= %d' % (allowed_version)\n\nclass ApiVersion:\n    def __init__(self, version):\n        self.version = version\n\nclass VkVersion:\n    def __init__(self, string):\n        split = string.split('.')\n        self.major = int(split[0])\n        self.minor = int(split[1])\n        if len(split) > 2:\n            assert len(split) == 3\n            self.patch = int(split[2])\n        else:\n            self.patch = None\n\n        # Sanity check.  The range bits are required by the definition of the\n        # VK_MAKE_VERSION macro\n        assert self.major < 1024 and self.minor < 1024\n        assert self.patch is None or self.patch < 4096\n        assert str(self) == string\n\n    def __str__(self):\n        ver_list = [str(self.major), str(self.minor)]\n        if self.patch is not None:\n            ver_list.append(str(self.patch))\n        return '.'.join(ver_list)\n\n    def c_vk_version(self):\n        ver_list = [str(self.major), str(self.minor), str(self.patch or 0)]\n        return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')'\n\n    def __int_ver(self):\n        # This is just an expansion of VK_VERSION\n        return (self.major << 22) | (self.minor << 12) | (self.patch or 0)\n\n    def __gt__(self, other):\n        # If only one of them has a patch version, \"ignore\" it by making\n        # other's patch version match self.\n        if (self.patch is None) != (other.patch is None):\n            other = copy.copy(other)\n            other.patch = self.patch\n\n        return self.__int_ver() > other.__int_ver()\n\n    def __le__(self, other):\n        return not self.__gt__(other)\n\n# Sort the extension list the way we expect: KHR, then EXT, then vendors\n# alphabetically. For digits, read them as a whole number sort that.\n# eg.: VK_KHR_8bit_storage < VK_KHR_16bit_storage < VK_EXT_acquire_xlib_display\ndef extension_order(ext):\n    order = []\n    for substring in re.split('(KHR|EXT|[0-9]+)', ext.name):\n        if substring == 'KHR':\n            order.append(1)\n        if substring == 'EXT':\n            order.append(2)\n        elif substring.isdigit():\n            order.append(int(substring))\n        else:\n            order.append(substring)\n    return order\n\ndef get_all_exts_from_xml(xml, api='vulkan'):\n    \"\"\" Get a list of all Vulkan extensions. \"\"\"\n\n    xml = et.parse(xml)\n\n    extensions = []\n    for ext_elem in xml.findall('.extensions/extension'):\n        ext = Extension.from_xml(ext_elem)\n        if api in ext.supported:\n            extensions.append(ext)\n\n    return sorted(extensions, key=extension_order)\n\ndef init_exts_from_xml(xml, extensions, platform_defines):\n    \"\"\" Walk the Vulkan XML and fill out extra extension information. \"\"\"\n\n    xml = et.parse(xml)\n\n    ext_name_map = {}\n    for ext in extensions:\n        ext_name_map[ext.name] = ext\n\n    # KHR_display is missing from the list.\n    platform_defines.append('VK_USE_PLATFORM_DISPLAY_KHR')\n    for platform in xml.findall('./platforms/platform'):\n        platform_defines.append(platform.attrib['protect'])\n\n    for ext_elem in xml.findall('.extensions/extension'):\n        ext_name = ext_elem.attrib['name']\n        if ext_name not in ext_name_map:\n            continue\n\n        ext = ext_name_map[ext_name]\n        ext.type = ext_elem.attrib['type']\n\nclass Requirements:\n    def __init__(self, core_version=None):\n        self.core_version = core_version\n        self.extensions = []\n        self.guard = None\n\n    def add_extension(self, ext):\n        for e in self.extensions:\n            if e == ext:\n                return;\n            assert e.name != ext.name\n\n        self.extensions.append(ext)\n\ndef filter_api(elem, api):\n    if 'api' not in elem.attrib:\n        return True\n\n    return api in elem.attrib['api'].split(',')\n\ndef get_alias(aliases, name):\n    if name in aliases:\n        # in case the spec registry adds an alias chain later\n        return get_alias(aliases, aliases[name])\n    return name\n\ndef get_all_required(xml, thing, api, beta):\n    things = {}\n    aliases = {}\n    for struct in xml.findall('./types/type[@category=\"struct\"][@alias]'):\n        if not filter_api(struct, api):\n            continue\n\n        name = struct.attrib['name']\n        alias = struct.attrib['alias']\n        aliases[name] = alias\n\n    for feature in xml.findall('./feature'):\n        if not filter_api(feature, api):\n            continue\n\n        version = VkVersion(feature.attrib['number'])\n        for t in feature.findall('./require/' + thing):\n            name = t.attrib['name']\n            if name in things:\n                assert things[name].core_version <= version\n            else:\n                things[name] = Requirements(core_version=version)\n\n    for extension in xml.findall('.extensions/extension'):\n        ext = Extension.from_xml(extension)\n        if api not in ext.supported:\n            continue\n\n        if beta != 'true' and ext.provisional:\n            continue\n\n        for require in extension.findall('./require'):\n            if not filter_api(require, api):\n                continue\n\n            for t in require.findall('./' + thing):\n                name = get_alias(aliases, t.attrib['name'])\n                r = things.setdefault(name, Requirements())\n                r.add_extension(ext)\n\n    platform_defines = {}\n    for platform in xml.findall('./platforms/platform'):\n        name = platform.attrib['name']\n        define = platform.attrib['protect']\n        platform_defines[name] = define\n\n    for req in things.values():\n        if req.core_version is not None:\n            continue\n\n        for ext in req.extensions:\n            if ext.platform in platform_defines:\n                req.guard = platform_defines[ext.platform]\n                break\n\n    return things\n\n# Mapping between extension name and the android version in which the extension\n# was whitelisted in Android CTS's dEQP-VK.info.device_extensions and\n# dEQP-VK.api.info.android.no_unknown_extensions, excluding those blocked by\n# android.graphics.cts.VulkanFeaturesTest#testVulkanBlockedExtensions.\nALLOWED_ANDROID_VERSION = {\n    # checkInstanceExtensions on oreo-cts-release\n    \"VK_KHR_surface\": 26,\n    \"VK_KHR_display\": 26,\n    \"VK_KHR_android_surface\": 26,\n    \"VK_KHR_mir_surface\": 26,\n    \"VK_KHR_wayland_surface\": 26,\n    \"VK_KHR_win32_surface\": 26,\n    \"VK_KHR_xcb_surface\": 26,\n    \"VK_KHR_xlib_surface\": 26,\n    \"VK_KHR_get_physical_device_properties2\": 26,\n    \"VK_KHR_get_surface_capabilities2\": 26,\n    \"VK_KHR_external_memory_capabilities\": 26,\n    \"VK_KHR_external_semaphore_capabilities\": 26,\n    \"VK_KHR_external_fence_capabilities\": 26,\n    # on pie-cts-release\n    \"VK_KHR_device_group_creation\": 28,\n    \"VK_KHR_get_display_properties2\": 28,\n    # on android10-tests-release\n    \"VK_KHR_surface_protected_capabilities\": 29,\n    # on android13-tests-release\n    \"VK_KHR_portability_enumeration\": 33,\n\n    # checkDeviceExtensions on oreo-cts-release\n    \"VK_KHR_swapchain\": 26,\n    \"VK_KHR_display_swapchain\": 26,\n    \"VK_KHR_sampler_mirror_clamp_to_edge\": 26,\n    \"VK_KHR_shader_draw_parameters\": 26,\n    \"VK_KHR_maintenance1\": 26,\n    \"VK_KHR_push_descriptor\": 26,\n    \"VK_KHR_descriptor_update_template\": 26,\n    \"VK_KHR_incremental_present\": 26,\n    \"VK_KHR_shared_presentable_image\": 26,\n    \"VK_KHR_storage_buffer_storage_class\": 26,\n    \"VK_KHR_16bit_storage\": 26,\n    \"VK_KHR_get_memory_requirements2\": 26,\n    \"VK_KHR_external_memory\": 26,\n    \"VK_KHR_external_memory_fd\": 26,\n    \"VK_KHR_external_memory_win32\": 26,\n    \"VK_KHR_external_semaphore\": 26,\n    \"VK_KHR_external_semaphore_fd\": 26,\n    \"VK_KHR_external_semaphore_win32\": 26,\n    \"VK_KHR_external_fence\": 26,\n    \"VK_KHR_external_fence_fd\": 26,\n    \"VK_KHR_external_fence_win32\": 26,\n    \"VK_KHR_win32_keyed_mutex\": 26,\n    \"VK_KHR_dedicated_allocation\": 26,\n    \"VK_KHR_variable_pointers\": 26,\n    \"VK_KHR_relaxed_block_layout\": 26,\n    \"VK_KHR_bind_memory2\": 26,\n    \"VK_KHR_maintenance2\": 26,\n    \"VK_KHR_image_format_list\": 26,\n    \"VK_KHR_sampler_ycbcr_conversion\": 26,\n    # on oreo-mr1-cts-release\n    \"VK_KHR_draw_indirect_count\": 27,\n    # on pie-cts-release\n    \"VK_KHR_device_group\": 28,\n    \"VK_KHR_multiview\": 28,\n    \"VK_KHR_maintenance3\": 28,\n    \"VK_KHR_create_renderpass2\": 28,\n    \"VK_KHR_driver_properties\": 28,\n    # on android10-tests-release\n    \"VK_KHR_shader_float_controls\": 29,\n    \"VK_KHR_shader_float16_int8\": 29,\n    \"VK_KHR_8bit_storage\": 29,\n    \"VK_KHR_depth_stencil_resolve\": 29,\n    \"VK_KHR_swapchain_mutable_format\": 29,\n    \"VK_KHR_shader_atomic_int64\": 29,\n    \"VK_KHR_vulkan_memory_model\": 29,\n    \"VK_KHR_swapchain_mutable_format\": 29,\n    \"VK_KHR_uniform_buffer_standard_layout\": 29,\n    # on android11-tests-release\n    \"VK_KHR_imageless_framebuffer\": 30,\n    \"VK_KHR_shader_subgroup_extended_types\": 30,\n    \"VK_KHR_buffer_device_address\": 30,\n    \"VK_KHR_separate_depth_stencil_layouts\": 30,\n    \"VK_KHR_timeline_semaphore\": 30,\n    \"VK_KHR_spirv_1_4\": 30,\n    \"VK_KHR_pipeline_executable_properties\": 30,\n    \"VK_KHR_shader_clock\": 30,\n    # blocked by testVulkanBlockedExtensions\n    # \"VK_KHR_performance_query\": 30,\n    \"VK_KHR_shader_non_semantic_info\": 30,\n    \"VK_KHR_copy_commands2\": 30,\n    # on android12-tests-release\n    \"VK_KHR_shader_terminate_invocation\": 31,\n    \"VK_KHR_ray_tracing_pipeline\": 31,\n    \"VK_KHR_ray_query\": 31,\n    \"VK_KHR_acceleration_structure\": 31,\n    \"VK_KHR_pipeline_library\": 31,\n    \"VK_KHR_deferred_host_operations\": 31,\n    \"VK_KHR_fragment_shading_rate\": 31,\n    \"VK_KHR_zero_initialize_workgroup_memory\": 31,\n    \"VK_KHR_workgroup_memory_explicit_layout\": 31,\n    \"VK_KHR_synchronization2\": 31,\n    \"VK_KHR_shader_integer_dot_product\": 31,\n    # on android13-tests-release\n    \"VK_KHR_dynamic_rendering\": 33,\n    \"VK_KHR_format_feature_flags2\": 33,\n    \"VK_KHR_global_priority\": 33,\n    \"VK_KHR_maintenance4\": 33,\n    \"VK_KHR_portability_subset\": 33,\n    \"VK_KHR_present_id\": 33,\n    \"VK_KHR_present_wait\": 33,\n    \"VK_KHR_shader_subgroup_uniform_control_flow\": 33,\n    # on android14-tests-release\n    \"VK_KHR_fragment_shader_barycentric\": 34,\n    \"VK_KHR_ray_tracing_maintenance1\": 34,\n    # blocked by testVulkanBlockedExtensions\n    # \"VK_KHR_video_decode_h264\": 34,\n    # \"VK_KHR_video_decode_h265\": 34,\n    # \"VK_KHR_video_decode_queue\": 34,\n    # \"VK_KHR_video_queue\": 34,\n    # on android15-tests-release\n    \"VK_KHR_calibrated_timestamps\": 35,\n    \"VK_KHR_cooperative_matrix\": 35,\n    \"VK_KHR_dynamic_rendering_local_read\": 35,\n    \"VK_KHR_index_type_uint8\": 35,\n    \"VK_KHR_line_rasterization\": 35,\n    \"VK_KHR_load_store_op_none\": 35,\n    \"VK_KHR_maintenance5\": 35,\n    \"VK_KHR_maintenance6\": 35,\n    \"VK_KHR_map_memory2\": 35,\n    \"VK_KHR_ray_tracing_position_fetch\": 35,\n    \"VK_KHR_shader_expect_assume\": 35,\n    \"VK_KHR_shader_float_controls2\": 35,\n    \"VK_KHR_shader_maximal_reconvergence\": 35,\n    \"VK_KHR_shader_quad_control\": 35,\n    \"VK_KHR_shader_subgroup_rotate\": 35,\n    \"VK_KHR_vertex_attribute_divisor\": 35,\n    # blocked by testVulkanBlockedExtensions\n    # \"VK_KHR_video_decode_av1\": 35,\n    # \"VK_KHR_video_encode_h264\": 35,\n    # \"VK_KHR_video_encode_h265\": 35,\n    # \"VK_KHR_video_encode_queue\": 35,\n    # \"VK_KHR_video_maintenance1\": 35,\n\n    # testNoUnknownExtensions on oreo-cts-release\n    \"VK_GOOGLE_display_timing\": 26,\n    # on pie-cts-release\n    \"VK_ANDROID_external_memory_android_hardware_buffer\": 28,\n    # on android11-tests-release\n    \"VK_GOOGLE_decorate_string\": 30,\n    \"VK_GOOGLE_hlsl_functionality1\": 30,\n    # on android13-tests-release\n    \"VK_GOOGLE_surfaceless_query\": 33,\n    # on android15-tests-release\n    \"VK_ANDROID_external_format_resolve\": 35,\n\n    # this HAL extension is always allowed and will be filtered out by the\n    # loader\n    \"VK_ANDROID_native_buffer\": 26,\n}\n\n# Extensions with these prefixes are checked in Android CTS, and thus must be\n# whitelisted per the preceding dict.\nANDROID_EXTENSION_WHITELIST_PREFIXES = (\n    \"VK_KHX\",\n    \"VK_KHR\",\n    \"VK_GOOGLE\",\n    \"VK_ANDROID\"\n)\n"
  },
  {
    "path": "bin/vk_extensions_gen.py",
    "content": "COPYRIGHT = \"\"\"\\\n/*\n * Copyright 2017 Intel Corporation\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * 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, sub license, 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 (including the\n * next paragraph) shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n * ANY 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\"\"\"\n\nimport argparse\n\nfrom mako.template import Template\n\n# Mesa-local imports must be declared in meson variable\n# '{file_without_suffix}_depend_files'.\nfrom vk_extensions import get_all_exts_from_xml, init_exts_from_xml\n\n_TEMPLATE_H = Template(COPYRIGHT + \"\"\"\n\n#ifndef VK_EXTENSIONS_H\n#define VK_EXTENSIONS_H\n\n#include <stdbool.h>\n\n<%def name=\"extension_table(type, extensions)\">\n#define VK_${type.upper()}_EXTENSION_COUNT ${len(extensions)}\n\nextern const VkExtensionProperties vk_${type}_extensions[];\n\nstruct vk_${type}_extension_table {\n   union {\n      bool extensions[VK_${type.upper()}_EXTENSION_COUNT];\n      struct {\n%for ext in extensions:\n         bool ${ext.name[3:]};\n%endfor\n      };\n\n      /* Workaround for \"error: too many initializers for vk_${type}_extension_table\" */\n      struct {\n%for ext in extensions:\n         bool ${ext.name[3:]};\n%endfor\n      } table;\n   };\n};\n</%def>\n\n${extension_table('instance', instance_extensions)}\n${extension_table('device', device_extensions)}\n\nstruct vk_physical_device;\n\n#ifdef ANDROID_STRICT\nextern const struct vk_instance_extension_table vk_android_allowed_instance_extensions;\nextern const struct vk_device_extension_table vk_android_allowed_device_extensions;\n#endif\n\n#endif /* VK_EXTENSIONS_H */\n\"\"\")\n\n_TEMPLATE_C = Template(COPYRIGHT + \"\"\"\n#include \"vulkan/vulkan_core.h\"\n\n#include \"vk_extensions.h\"\n\nconst VkExtensionProperties vk_instance_extensions[VK_INSTANCE_EXTENSION_COUNT] = {\n%for ext in instance_extensions:\n   {\"${ext.name}\", ${ext.ext_version}},\n%endfor\n};\n\nconst VkExtensionProperties vk_device_extensions[VK_DEVICE_EXTENSION_COUNT] = {\n%for ext in device_extensions:\n   {\"${ext.name}\", ${ext.ext_version}},\n%endfor\n};\n\n#ifdef ANDROID_STRICT\nconst struct vk_instance_extension_table vk_android_allowed_instance_extensions = {\n%for ext in instance_extensions:\n   .${ext.name[3:]} = ${ext.c_android_condition()},\n%endfor\n};\n\nconst struct vk_device_extension_table vk_android_allowed_device_extensions = {\n%for ext in device_extensions:\n   .${ext.name[3:]} = ${ext.c_android_condition()},\n%endfor\n};\n#endif\n\"\"\")\n\ndef gen_extensions(xml_files, extensions, out_c, out_h):\n    platform_defines = []\n    for filename in xml_files:\n        init_exts_from_xml(filename, extensions, platform_defines)\n\n    for ext in extensions:\n        assert ext.type in {'instance', 'device'}\n\n    template_env = {\n        'instance_extensions': [e for e in extensions if e.type == 'instance'],\n        'device_extensions': [e for e in extensions if e.type == 'device'],\n        'platform_defines': platform_defines,\n    }\n\n    if out_h:\n        with open(out_h, 'w', encoding='utf-8') as f:\n            f.write(_TEMPLATE_H.render(**template_env))\n\n    if out_c:\n        with open(out_c, 'w', encoding='utf-8') as f:\n            f.write(_TEMPLATE_C.render(**template_env))\n\n\ndef main():\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--out-c', help='Output C file.')\n    parser.add_argument('--out-h', help='Output H file.')\n    parser.add_argument('--xml',\n                        help='Vulkan API XML file.',\n                        required=True,\n                        action='append',\n                        dest='xml_files')\n    args = parser.parse_args()\n\n    extensions = []\n    for filename in args.xml_files:\n        extensions += get_all_exts_from_xml(filename)\n\n    gen_extensions(args.xml_files, extensions, args.out_c, args.out_h)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "build-source.sh",
    "content": "#!/bin/sh\n\nVERSION=$(git describe --tags --dirty)\nNAME=MangoHud-${VERSION}\nTAR_NAME=${NAME}-Source.tar.xz\nDFSG_TAR_NAME=${NAME}-Source-DFSG.tar.xz\n\n# remove existing files\nrm -rf sourcedir\nrm -rf ${NAME}\nrm -f ${TAR_NAME}\nrm -f ${DFSG_TAR_NAME}\n\n# create tarball with meson\nmeson setup sourcedir\nmeson dist --formats=xztar --include-subprojects --no-tests -C sourcedir\nmv sourcedir/meson-dist/*.tar.xz ${TAR_NAME}\n\n# create DFSG compliant version\n# unpack since tarball is compressed\nmkdir ${NAME}\ntar -xf ${TAR_NAME} --strip 1 -C ${NAME}\n# nvml.h is not DFSG compliant\nrm ${NAME}/include/nvml.h\n# minhook not needed\nrm -r ${NAME}/modules/minhook\n# spdlog from system\nrm -r ${NAME}/subprojects/spdlog-*\n# nlohmann_json from system\nrm -r ${NAME}/subprojects/nlohmann_json-*\n# remove some vulkan clutter\nrm -r ${NAME}/subprojects/Vulkan-Headers-*/cmake ${NAME}/subprojects/Vulkan-Headers-*/BUILD.gn\n# remove some dear imgui clutter\nrm -rf ${NAME}/subprojects/imgui-*/examples\n# compress new sources\ntar -cJf ${DFSG_TAR_NAME} ${NAME}\n\n# cleanup\nrm -r sourcedir\nrm -r ${NAME}\n"
  },
  {
    "path": "build-srt.sh",
    "content": "#!/usr/bin/env bash\n# Specialized build script for Steam Runtime SDK docker\nset -e\n\nIFS=\" \" read -ra debian_chroot < /etc/debian_chroot\nLOCAL_CC=${CC:-gcc-5}\nLOCAL_CXX=${CXX:-g++-5}\nRUNTIME=${RUNTIME:-${debian_chroot[1]}}\nSRT_VERSION=${SRT_VERSION:-${debian_chroot[2]}}\nVERSION=$(git describe --long --tags --always | sed 's/\\([^-]*-g\\)/r\\1/;s/-/./g;s/^v//')\n\ndependencies() {\n\n    if [[ ! -f build-srt/release/usr/lib/libMangoHud.so ]]; then\n        install() {\n            set +e\n            for i in ${DEPS[@]}; do\n                dpkg-query -s \"$i\" &> /dev/null\n                if [[ $? == 1 ]]; then\n                    INSTALL=\"$INSTALL\"\"$i \"\n                fi\n            done\n            if [[ ! -z \"$INSTALL\" ]]; then\n                apt-get update\n                apt-get -y install $INSTALL\n            fi\n            set -e\n        }\n\n        echo \"# Checking Dependencies\"\n        DEPS=(${LOCAL_CC}-multilib ${LOCAL_CXX}-multilib unzip)\n        install\n\n\n        # use py3.5 with scout, otherwise hope python is new enough\n        set +e\n        which python3.5 >/dev/null\n        if [ $? -eq 0 ]; then\n            # py3.2 is weird\n            ln -sf python3.5 /usr/bin/python3\n        fi\n        set -e\n\n        if [[ ! -f ./bin/get-pip.py ]]; then\n            curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o bin/get-pip.py\n            python3 ./bin/get-pip.py\n        fi\n        pip3 install 'meson>=0.54' mako\n\n        if [[ ! -f /usr/include/NVCtrl/NVCtrl.h ]]; then\n            curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb\n            curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl-dev_440.64-0ubuntu1_amd64.deb\n            dpkg -i libxnvctrl0_440.64-0ubuntu1_amd64.deb libxnvctrl-dev_440.64-0ubuntu1_amd64.deb\n        fi\n\n        # preinstalled 7.10.xxxx\n        #if [[ ! -f /usr/local/bin/glslangValidator ]]; then\n        #    curl -LO https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip\n        #    unzip glslang-master-linux-Release.zip bin/glslangValidator\n        #    /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/\n        #    rm bin/glslangValidator glslang-master-linux-Release.zip\n        #fi\n    fi\n}\n\nconfigure() {\n    dependencies\n    git submodule update --init\n    if [[ ! -f \"build-srt/meson64/build.ninja\" ]]; then\n        export CC=\"${LOCAL_CC}\"\n        export CXX=\"${LOCAL_CXX}\"\n        meson build-srt/meson64 --libdir lib/mangohud/lib --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS}\n    fi\n    if [[ ! -f \"build-srt/meson32/build.ninja\" ]]; then\n        export CC=\"${LOCAL_CC} -m32\"\n        export CXX=\"${LOCAL_CXX} -m32\"\n        export PKG_CONFIG_PATH=\"/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}\"\n        meson build-srt/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS}\n    fi\n}\n\nbuild() {\n    if [[ ! -f \"build-srt/meson64/build.ninja\" || ! -f \"build-srt/meson32/build.ninja\" ]]; then\n        configure $@\n    fi\n    DESTDIR=\"$PWD/build-srt/release\" ninja -C build-srt/meson32 install\n    DESTDIR=\"$PWD/build-srt/release\" ninja -C build-srt/meson64 install\n}\n\npackage() {\n    LIB=\"build-srt/release/usr/lib/mangohud/lib/libMangoHud.so\"\n    LIB32=\"build-srt/release/usr/lib/mangohud/lib32/libMangoHud.so\"\n    if [[ ! -f \"$LIB\" || \"$LIB\" -ot \"build-srt/meson64/src/libMangoHud.so\" ]]; then\n        build\n    fi\n    tar --numeric-owner --owner=0 --group=0 \\\n        -C build-srt/release -cvf \"build-srt/MangoHud-package.tar\" .\n}\n\nrelease() {\n    rm build-srt/MangoHud-package.tar\n    mkdir -p build-srt/MangoHud\n    package\n    cp --preserve=mode bin/mangohud-setup.sh build-srt/MangoHud/mangohud-setup.sh\n    cp build-srt/MangoHud-package.tar build-srt/MangoHud/MangoHud-package.tar\n    tar --numeric-owner --owner=0 --group=0 \\\n        -C build-srt -czvf build-srt/MangoHud-${VERSION}_${RUNTIME}-${SRT_VERSION}.tar.gz MangoHud\n}\n\nclean() {\n    rm -rf \"build-srt/\"\n}\n\nusage() {\n    if test -z $1; then\n        echo \"Unrecognized command argument: $a\"\n    else\n        echo \"$0 requires one argument\"\n    fi\n    echo -e \"\\nUsage: $0 <command>\\n\"\n    echo \"Available commands:\"\n    echo -e \"\\tpull\\t\\tPull latest commits (code) from Git\"\n    echo -e \"\\tconfigure\\tEnsures that dependencies are installed, updates git submodules, and generates files needed for building MangoHud. This is automatically run by the build command\"\n    echo -e \"\\tbuild\\t\\tIf needed runs configure and then builds (compiles) MangoHud\"\n    echo -e \"\\tpackage\\t\\tRuns build if needed and then builds a tar package from MangoHud\"\n    echo -e \"\\tclean\\t\\tRemoves build directory\"\n    echo -e \"\\trelease\\t\\tBuilds a MangoHud release tar package\"\n}\n\nif [[ -z $@ ]]; then\n    usage no-args\nfi\n\nwhile [ $# -gt 0 ]; do\n    OPTS=()\n    arg=\"$1\"\n    shift\n\n    while [ $# -gt 0 ] ; do\n        case $1 in\n        -*)\n            OPTS+=(\"$1\")\n            shift\n        ;;\n        *)\n            break\n        ;;\n        esac;\n    done\n\n    echo -e \"\\e[1mCommand:\\e[92m\" $arg \"\\e[94m\"${OPTS[@]}\"\\e[39m\\e[0m\"\n    case $arg in\n        \"configure\") configure ${OPTS[@]};;\n        \"build\") build ${OPTS[@]};;\n        \"package\") package;;\n        \"clean\") clean;;\n        \"release\") release;;\n        *)\n            usage\n    esac\ndone\n"
  },
  {
    "path": "build-with-srt-docker.sh",
    "content": "#!/usr/bin/env bash\n# Usage example: $0 master soldier 0.20210618.0\nset -u\n\nif [ $# -eq 2 ]; then\n  echo Specify runtime version too\n  exit 1\nfi\n\nSRCDIR=$PWD\nBRANCH=\"${1:-master}\"\n# soldier 0.20210618.0 or newer\n# scout 0.20210630.0 or newer\nRUNTIME=\"${2:-soldier}\"\nVERSION=\"${3:-0.20210618.0}\"\nIMAGE=\"steamrt_${RUNTIME}_${VERSION}_amd64:mango-${RUNTIME}\"\nBASEURL=\"https://repo.steampowered.com/steamrt-images-${RUNTIME}/snapshots/${VERSION}\"\nCACHEDIR=\"./cache/steamrt-images-${RUNTIME}/snapshots/${VERSION}\"\n\nmkdir -p \"${CACHEDIR}\"\n\necho -e \"\\e[1mBuilding branch \\e[92m${BRANCH}\\e[39m using \\e[92m${RUNTIME}:${VERSION}\\e[39m runtime\\e[0m\"\n\nif ! docker inspect --type=image ${IMAGE} 2>&1 >/dev/null ; then\n  rm -fr ./cache/empty\n  set -e\n  mkdir -p ./cache/empty\n  sed \"s/%RUNTIME%/${RUNTIME}/g\" steamrt.Dockerfile.in  > ./cache/steamrt.Dockerfile\n\n  wget -P \"${CACHEDIR}\" -c ${BASEURL}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-${RUNTIME}-sysroot.tar.gz\n  cp --reflink=always \"${CACHEDIR}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-${RUNTIME}-sysroot.tar.gz\" ./cache/empty/\n  docker build -f ./cache/steamrt.Dockerfile -t ${IMAGE} ./cache/empty\nfi\n\ndocker run --entrypoint=/bin/sh --rm -i -v \"${SRCDIR}/srt-output:/output\" ${IMAGE} << EOF\nexport RUNTIME=${RUNTIME}\nexport SRT_VERSION=${VERSION}\ngit clone git://github.com/flightlessmango/MangoHud.git . --branch ${BRANCH} --recurse-submodules --progress\n./build-srt.sh clean build package release\ncp -v build-srt/MangoHud*tar.gz /output/\nEOF\n"
  },
  {
    "path": "build.sh",
    "content": "#!/usr/bin/env bash\nset -e\n\n# Import the variables for dependencies\nsource ./build_deps.sh\n\nOS_RELEASE_FILES=(\"/etc/os-release\" \"/usr/lib/os-release\")\nXDG_DATA_HOME=\"${XDG_DATA_HOME:-$HOME/.local/share}\"\nXDG_CONFIG_HOME=\"${XDG_CONFIG_HOME:-$HOME/.config}\"\nCONFIG_DIR=\"$XDG_CONFIG_HOME/MangoHud\"\nVERSION=$(git describe --long --tags --always | sed 's/\\([^-]*-g\\)/r\\1/;s/-/./g;s/^v//')\nSU_CMD=$(command -v sudo || command -v doas || echo)\nMACHINE=$(uname -m || echo)\n\n# doas requires a double dash if the command it runs will include any dashes,\n# so append a double dash to the command\n[[ $SU_CMD == *doas ]] && SU_CMD=\"$SU_CMD -- \"\n\n# Correctly identify the os-release file.\nfor os_release in ${OS_RELEASE_FILES[@]} ; do\n    if [[ ! -e \"${os_release}\" ]]; then\n        continue\n    fi\n    DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\\L\\2/p' ${os_release} | sed 's/\"//g')\ndone\n\ndependencies() {\n    if [[ ! -f build/release/usr/lib/libMangoHud.so ]]; then\n        missing_deps() {\n            echo \"# Missing dependencies:$INSTALL\"\n            read -rp \"Do you wish the script to install these packages? [y/N]\" PERMISSION\n            case \"$PERMISSION\" in\n                \"y\"|\"Y\") echo \"Attempting to install missing packages\"; sleep 0.5;;\n                *) echo \"Continuing with missing dependencies\"; sleep 1;;\n            esac\n        }\n        dep_install() {\n            set +e\n            for i in $(eval echo $DEPS); do\n                $MANAGER_QUERY \"$i\" &> /dev/null\n                if [[ $? == 1 ]]; then\n                    INSTALL=\"$INSTALL\"\"$i \"\n                fi\n            done\n            if [[ ! -z \"$INSTALL\" ]]; then\n                missing_deps\n                if [[ \"$PERMISSION\" == \"Y\" || \"$PERMISSION\" == \"y\" ]]; then\n                    $SU_CMD $MANAGER_INSTALL $INSTALL\n                fi\n            fi\n            set -e\n        }\n\n        for i in $DISTRO; do\n        echo \"# Checking dependencies for \\\"$i\\\"\"\n        case $i in\n            *arch*|*manjaro*|*artix*|*SteamOS*)\n                MANAGER_QUERY=\"pacman -Q\"\n                MANAGER_INSTALL=\"pacman -S\"\n                DEPS=\"{${DEPS_ARCH}}\"\n                dep_install\n                break\n            ;;\n            *fedora*|*nobara*)\n                MANAGER_QUERY=\"dnf list installed\"\n                MANAGER_INSTALL=\"dnf install\"\n                DEPS=\"{${DEPS_FEDORA}}\"\n                dep_install\n\n                unset INSTALL\n                DEPS=\"{glibc-devel.i686,libstdc++-devel.i686,libX11-devel.i686,wayland-devel.i686,libxkbcommon-devel.i686}\"\n                dep_install\n                break\n            ;;\n\n            *debian*|*ubuntu*|*deepin*|*pop*)\n                MANAGER_QUERY=\"dpkg-query -s\"\n                MANAGER_INSTALL=\"apt install\"\n                DEPS=\"{${DEPS_DEBIAN}}\"\n\n                if ! dpkg --print-foreign-architectures | grep i386 > /dev/null; then\n                    echo \"i386 architecture is not enabled. adding it.\"\n                    $SU_CMD dpkg --add-architecture i386\n                    $SU_CMD apt update\n                fi\n\n                dep_install\n\n                if [[ ! -f /usr/local/bin/glslangValidator ]]; then\n                    wget https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip\n                    unzip glslang-master-linux-Release.zip bin/glslangValidator\n                    $SU_CMD /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/\n                    rm bin/glslangValidator glslang-master-linux-Release.zip\n                fi\n                break\n            ;;\n            *suse*)\n                echo \"You may have to enable packman repository for some extra packages: ${DEPS_SUSE_EXTRA}\"\n                echo \"Leap:       zypper ar -cfp 90 https://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Leap_15.1/ packman\"\n                echo \"Tumbleweed: zypper ar -cfp 90 http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/ packman\"\n\n                MANAGER_QUERY=\"rpm -q\"\n                MANAGER_INSTALL=\"zypper install\"\n                DEPS=\"{${DEPS_SUSE},${DEPS_SUSE_EXTRA}}\"\n                dep_install\n\n                if [[ $(pip3 show meson; echo $?) == 1 ]]; then\n                    $SU_CMD pip3 install 'meson>=0.54'\n                fi\n                break\n            ;;\n            *solus*)\n                unset MANAGER_QUERY\n                unset DEPS\n                MANAGER_INSTALL=\"eopkg it\"\n\n                local packages=(${DEPS_SOLUS//,/ })\n\n                # eopkg doesn't emit exit codes properly, so use the python API to find if a package is installed.\n                for package in ${packages[@]}; do\n                    python -c \"import pisi.db; import sys; idb = pisi.db.installdb.InstallDB(); sys.exit(0 if idb.has_package(\\\"${package}\\\") else 1)\"\n                    if [[ $? -ne 0 ]]; then\n                        INSTALL=\"${INSTALL}\"\"${package} \"\n                    fi\n                done\n\n                # likewise, ensure the whole system.devel component is satisfied\n                python -c \"import pisi.db; import sys; idb = pisi.db.installdb.InstallDB(); cdb = pisi.db.componentdb.ComponentDB(); mpkgs = [x for x in cdb.get_packages('system.devel') if not idb.has_package(x)]; sys.exit(0 if len(mpkgs) == 0 else 1)\"\n\n                if [[ $? -ne 0 ]]; then\n                    INSTALL=\"${INSTALL}\"\"-c system.devel \"\n                fi\n                dep_install\n                break\n                ;;\n            *)\n                echo \"# Unable to find distro information!\"\n                echo \"# Attempting to build regardless\"\n        esac\n        done\n    fi\n}\n\nconfigure() {\n    dependencies\n    git submodule update --init --depth 50\n    CONFIGURE_OPTS=\"-Dwerror=true\"\n    if [[ ! -f \"build/meson64/build.ninja\" ]]; then\n        meson setup build/meson64 --libdir lib/mangohud/lib64 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS}\n    fi\n    if [[ ! -f \"build/meson32/build.ninja\" && \"$MACHINE\" = \"x86_64\" ]]; then\n        export CC=\"gcc -m32\"\n        export CXX=\"g++ -m32\"\n        export PKG_CONFIG_PATH=\"/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}\"\n        meson setup build/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS}\n    fi\n}\n\nbuild() {\n    if [[ ! -f \"build/meson64/build.ninja\" ]]; then\n        configure $@\n    fi\n    DESTDIR=\"$PWD/build/release\" ninja -C build/meson64 install\n\n    if [ \"$MACHINE\" = \"x86_64\" ]; then\n        DESTDIR=\"$PWD/build/release\" ninja -C build/meson32 install\n    fi\n\n    sed -i 's:/usr/\\\\$LIB:/usr/lib/mangohud/\\\\$LIB:g' \"$PWD/build/release/usr/bin/mangohud\"\n}\n\npackage() {\n    LIB=\"build/release/usr/lib/mangohud/lib64/libMangoHud.so\"\n    LIB32=\"build/release/usr/lib/mangohud/lib32/libMangoHud.so\"\n    if [[ ! -f \"$LIB\" || \"$LIB\" -ot \"build/meson64/src/libMangoHud.so\" ]]; then\n        build\n    fi\n    tar --numeric-owner --owner=0 --group=0 \\\n        -C build/release -cvf \"build/MangoHud-package.tar\" .\n}\n\nrelease() {\n    rm build/MangoHud-package.tar\n    mkdir -p build/MangoHud\n    package\n    cp --preserve=mode bin/mangohud-setup.sh build/MangoHud/mangohud-setup.sh\n    cp build/MangoHud-package.tar build/MangoHud/MangoHud-package.tar\n    tar --numeric-owner --owner=0 --group=0 \\\n        -C build -czvf build/MangoHud-$VERSION.tar.gz MangoHud\n}\n\nuninstall() {\n    [ \"$UID\" -eq 0 ] || exec $SU_CMD bash \"$0\" uninstall\n    rm -rfv \"/usr/lib/mangohud\"\n    rm -rfv \"/usr/share/doc/mangohud\"\n    rm -fv \"/usr/share/man/man1/mangohud.1\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/mangohud.json\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.json\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json\"\n    rm -fv \"/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json\"\n    rm -fv \"/usr/bin/mangohud\"\n    rm -fv \"/usr/bin/mangoplot\"\n    rm -fv \"/usr/bin/mangohud.x86\"\n}\n\ninstall() {\n    rm -rf \"$HOME/.local/share/MangoHud/\"\n    rm -f \"$HOME/.local/share/vulkan/implicit_layer.d/\"{mangohud32.json,mangohud64.json}\n\n    [ \"$UID\" -eq 0 ] || mkdir -pv \"${CONFIG_DIR}\"\n    [ \"$UID\" -eq 0 ] || build\n    [ \"$UID\" -eq 0 ] || exec $SU_CMD bash \"$0\" install\n\n    uninstall\n\n    DEFAULTLIB=lib32\n    for i in $DISTRO; do\n        case $i in\n            *arch*)\n            DEFAULTLIB=lib64\n            ;;\n        esac\n    done\n\n    if [ \"$MACHINE\" != \"x86_64\" ]; then\n        # Native libs\n        DEFAULTLIB=lib64\n    fi\n\n    echo DEFAULTLIB: $DEFAULTLIB\n    /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so\n    /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/lib/mangohud/lib64/libMangoHud_opengl.so\n    /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_shim.so /usr/lib/mangohud/lib64/libMangoHud_shim.so\n    if [ \"$MACHINE\" = \"x86_64\" ]; then\n      /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so\n      /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/lib/mangohud/lib32/libMangoHud_opengl.so\n      /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_shim.so /usr/lib/mangohud/lib32/libMangoHud_shim.so\n    fi\n\n    /usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json\n    /usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json\n    /usr/bin/install -Dvm644 ./build/release/usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1\n    /usr/bin/install -Dvm644 ./build/release/usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example\n    /usr/bin/install -vm755  ./build/release/usr/bin/mangohud /usr/bin/mangohud\n    /usr/bin/install -vm755  ./build/release/usr/bin/mangoplot /usr/bin/mangoplot\n\n    ln -sv $DEFAULTLIB /usr/lib/mangohud/lib\n\n    # FIXME get the triplet somehow\n    ln -sv lib64 /usr/lib/mangohud/x86_64\n    ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu\n    ln -sv . /usr/lib/mangohud/lib64/x86_64\n    ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu\n\n    ln -sv lib32 /usr/lib/mangohud/i686\n    ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu\n    ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu\n\n    mkdir -p /usr/lib/mangohud/tls\n    ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64\n    ln -sv ../lib32 /usr/lib/mangohud/tls/i686\n\n    # Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead\n    if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then\n        ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu\n    fi\n    if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then\n        ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu\n    fi\n    if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then\n        ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu\n    fi\n\n    # $LIB can be \"lib/tls/x86_64\"?\n    ln -sv ../tls /usr/lib/mangohud/lib/tls\n\n    #ln -sv lib64 /usr/lib/mangohud/aarch64-linux-gnu\n    #ln -sv lib64 /usr/lib/mangohud/arm-linux-gnueabihf\n\n    echo \"MangoHud Installed\"\n}\n\nreinstall() {\n    build\n    package\n    install\n}\n\nclean() {\n    rm -rf \"build\"\n    rm -rf subprojects/*/\n}\n\nusage() {\n    if test -z $1; then\n        echo \"Unrecognized command argument: $arg\"\n    else\n        echo \"$0 requires one argument\"\n    fi\n    echo -e \"\\nUsage: $0 <command>\\n\"\n    echo \"Available commands:\"\n    echo -e \"\\tpull\\t\\tPull latest commits (code) from Git\"\n    echo -e \"\\tconfigure\\tEnsures that dependencies are installed, updates git submodules, and generates files needed for building MangoHud. This is automatically run by the build command\"\n    echo -e \"\\tbuild\\t\\tIf needed runs configure and then builds (compiles) MangoHud\"\n    echo -e \"\\tpackage\\t\\tRuns build if needed and then builds a tar package from MangoHud\"\n    echo -e \"\\tinstall\\t\\tInstall MangoHud onto your system\"\n    echo -e \"\\treinstall\\tRuns build, then package, and finally install\"\n    echo -e \"\\tclean\\t\\tRemoves build directory\"\n    echo -e \"\\tuninstall\\tRemoves installed MangoHud files from your system\"\n    echo -e \"\\trelease\\t\\tBuilds a MangoHud release tar package\"\n}\n\nif [[ -z $@ ]]; then\n    usage no-args\nfi\n\nwhile [ $# -gt 0 ]; do\n    OPTS=()\n    arg=\"$1\"\n    shift\n\n    while [ $# -gt 0 ] ; do\n        case $1 in\n        -*)\n            OPTS+=(\"$1\")\n            shift\n        ;;\n        *)\n            break\n        ;;\n        esac;\n    done\n\n    echo -e \"\\e[1mCommand:\\e[92m\" $arg \"\\e[94m\"${OPTS[@]}\"\\e[39m\\e[0m\"\n    case $arg in\n        \"pull\") git pull ${OPTS[@]};;\n        \"configure\") configure ${OPTS[@]};;\n        \"build\") build ${OPTS[@]};;\n        \"build_dbg\") build --buildtype=debug -Dglibcxx_asserts=true ${OPTS[@]};;\n        \"package\") package;;\n        \"install\") install;;\n        \"reinstall\") reinstall;;\n        \"clean\") clean;;\n        \"uninstall\") uninstall;;\n        \"release\") release;;\n        *)\n            usage\n    esac\ndone\n"
  },
  {
    "path": "build_deps.sh",
    "content": "DEPS_ARCH=\"gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl,libdrm,python-numpy,python-matplotlib,libxkbcommon,lib32-libxkbcommon\"\nDEPS_FEDORA=\"meson,gcc,gcc-c++,libX11-devel,glslang,python3-mako,mesa-libGL-devel,libXNVCtrl-devel,dbus-devel,python3-numpy,python3-matplotlib,libstdc++-static,libstdc++-static.i686,libxkbcommon-devel,wayland-devel\"\nDEPS_DEBIAN=\"gcc,g++,gcc-multilib,g++-multilib,ninja-build,meson,python3-mako,python3-setuptools,python3-wheel,pkg-config,mesa-common-dev,libx11-dev,libxnvctrl-dev,libdbus-1-dev,python3-numpy,python3-matplotlib,libxkbcommon-dev,libxkbcommon-dev:i386,libwayland-dev,libwayland-dev:i386\"\nDEPS_SOLUS=\"mesalib-32bit-devel,glslang,libstdc++-32bit,glibc-32bit-devel,mako,numpy,matplotlib,libxkbcommon-devel\"\n\nDEPS_SUSE=\"gcc-c++,gcc-c++-32bit,libpkgconf-devel,ninja,python3-pip,python3-Mako,libX11-devel,glslang-devel,glibc-devel,glibc-devel-32bit,libstdc++-devel,libstdc++-devel-32bit,Mesa-libGL-devel,dbus-1-devel,python-numpy,python-matplotlib,libxkbcommon-devel,libxkbcommon-devel-32bit,wayland-devel-32bit\"\nDEPS_SUSE_EXTRA=\"libXNVCtrl-devel\"\n"
  },
  {
    "path": "control/setup.cfg",
    "content": "[metadata]\nname = mangohud_control\nversion = 0.0.1\nauthor = Simon Hallsten\nauthor_email = flightlessmangoyt@gmail.com\ndescription = control interface for mangohud\nclassifiers =\n    Programming Language :: Python :: 3\n    License :: OSI Approved :: MIT License\n    Operating System :: Linux\n\n[options]\npackage_dir =\n  = src\n\npackages = find:\npython_requires = >=3.6\n\n[options.packages.find]\nwhere = src\n\n[options.entry_points]\nconsole_scripts =\n    mangohud-control = control:main\n\n[pycodestyle]\nmax-line-length = 160"
  },
  {
    "path": "control/setup.py",
    "content": "import site\nimport sys\nfrom setuptools import setup\n\nif __name__ == \"__main__\":\n    setup()\n\n# See https://github.com/pypa/pip/issues/7953\nsite.ENABLE_USER_SITE = \"--user\" in sys.argv[1:]\n"
  },
  {
    "path": "control/src/control/__init__.py",
    "content": "#!/usr/bin/env python3\nimport os\nimport socket\nimport sys\nimport select\nfrom select import EPOLLIN, EPOLLPRI, EPOLLERR\nimport time\nfrom collections import namedtuple\nimport argparse\n\nTIMEOUT = 1.0 # seconds\n\nVERSION_HEADER = bytearray('MangoHudControlVersion', 'utf-8')\nDEVICE_NAME_HEADER = bytearray('DeviceName', 'utf-8')\nMANGOHUD_VERSION_HEADER = bytearray('MangoHudVersion', 'utf-8')\n\nDEFAULT_SERVER_ADDRESS = \"\\0mangohud\"\n\nclass Connection:\n    def __init__(self, path):\n        # Create a Unix Domain socket and connect\n        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)\n        try:\n            sock.connect(path)\n        except socket.error as msg:\n            print(msg)\n            sys.exit(1)\n\n        self.sock = sock\n\n        # initialize poll interface and register socket\n        epoll = select.epoll()\n        epoll.register(sock, EPOLLIN | EPOLLPRI | EPOLLERR)\n        self.epoll = epoll\n\n    def recv(self, timeout):\n        '''\n        timeout as float in seconds\n        returns:\n            - None on error or disconnection\n            - bytes() (empty) on timeout\n        '''\n\n        events = self.epoll.poll(timeout)\n        for ev in events:\n            (fd, event) = ev\n            if fd != self.sock.fileno():\n                continue\n\n            # check for socket error\n            if event & EPOLLERR:\n                return None\n\n            # EPOLLIN or EPOLLPRI, just read the message\n            msg = self.sock.recv(4096)\n\n            # socket disconnected\n            if len(msg) == 0:\n                return None\n\n            return msg\n\n        return bytes()\n\n    def send(self, msg):\n        self.sock.send(msg)\n\nclass MsgParser:\n    MSGBEGIN = bytes(':', 'utf-8')[0]\n    MSGEND = bytes(';', 'utf-8')[0]\n    MSGSEP = bytes('=', 'utf-8')[0]\n\n    def __init__(self, conn):\n        self.cmdpos = 0\n        self.parampos = 0\n        self.bufferpos = 0\n        self.reading_cmd = False\n        self.reading_param = False\n        self.buffer = None\n        self.cmd = bytearray(4096)\n        self.param = bytearray(4096)\n\n        self.conn = conn\n\n    def readCmd(self, ncmds, timeout=TIMEOUT):\n        '''\n        returns:\n            - None on error or disconnection\n            - bytes() (empty) on timeout\n        '''\n\n        parsed = []\n\n        remaining = timeout\n\n        while remaining > 0 and ncmds > 0:\n            now = time.monotonic()\n\n            if self.buffer == None:\n                self.buffer = self.conn.recv(remaining)\n                self.bufferpos = 0\n\n            # disconnected or error\n            if self.buffer == None:\n                return None\n\n            for i in range(self.bufferpos, len(self.buffer)):\n                c = self.buffer[i]\n                self.bufferpos += 1\n                if c == self.MSGBEGIN:\n                    self.cmdpos = 0\n                    self.parampos = 0\n                    self.reading_cmd = True\n                    self.reading_param = False\n                elif c == self.MSGEND:\n                    if not self.reading_cmd:\n                        continue\n                    self.reading_cmd = False\n                    self.reading_param = False\n\n                    cmd = self.cmd[0:self.cmdpos]\n                    param = self.param[0:self.parampos]\n                    self.reading_cmd = False\n                    self.reading_param = False\n\n                    parsed.append((cmd, param))\n                    ncmds -= 1\n                    if ncmds == 0:\n                        break\n                elif c == self.MSGSEP:\n                    if self.reading_cmd:\n                        self.reading_param = True\n                else:\n                    if self.reading_param:\n                        self.param[self.parampos] = c\n                        self.parampos += 1\n                    elif self.reading_cmd:\n                        self.cmd[self.cmdpos] = c\n                        self.cmdpos += 1\n\n            # if we read the entire buffer and didn't finish the command,\n            # throw it away\n            self.buffer = None\n\n            # check if we have time for another iteration\n            elapsed = time.monotonic() - now\n            remaining = max(0, remaining - elapsed)\n\n        # timeout\n        return parsed\n\ndef control(args):\n    if args.socket:\n        address = '\\0' + args.socket\n    else:\n        address = DEFAULT_SERVER_ADDRESS\n\n    conn = Connection(address)\n    msgparser = MsgParser(conn)\n\n    version = None\n    name = None\n    mangohud_version = None\n\n    msgs = msgparser.readCmd(3)\n\n    for m in msgs:\n        cmd, param = m\n        if cmd == VERSION_HEADER:\n            version = int(param)\n        elif cmd == DEVICE_NAME_HEADER:\n            name = param.decode('utf-8')\n        elif cmd == MANGOHUD_VERSION_HEADER:\n            mangohud_version = param.decode('utf-8')\n\n    if args.info:\n        info = \"Protocol Version: {}\\n\"\n        info += \"Device Name: {}\\n\"\n        info += \"MangoHud Version: {}\"\n        print(info.format(version, name, mangohud_version))\n\n\n    if args.cmd == 'toggle-logging':\n        conn.send(bytearray(':logging;', 'utf-8'))\n    elif args.cmd == 'start-logging':\n        conn.send(bytearray(':logging=1;', 'utf-8'))\n\n    elif args.cmd == 'stop-logging':\n        conn.send(bytearray(':logging=0;', 'utf-8'))\n        now = time.monotonic()\n        while True:\n            msg = str(conn.recv(3))\n            if \"LoggingFinished\" in msg:\n                print(\"Logging has stopped\")\n                exit(0)\n            elapsed = time.monotonic() - now\n            if elapsed > 3:\n                print(\"Stop logging timed out\")\n                exit(1)\n\n    elif args.cmd == 'toggle-hud':\n        conn.send(bytearray(':hud;', 'utf-8'))\n    elif args.cmd == 'toggle-fcat':\n        conn.send(bytearray(':fcat;', 'utf-8'))\n\ndef main():\n    parser = argparse.ArgumentParser(description='MangoHud control client')\n    parser.add_argument('--info', action='store_true', help='Print info from socket')\n    parser.add_argument('--socket', '-s', type=str, help='Path to socket')\n\n    commands = parser.add_subparsers(help='commands to run', dest='cmd')\n    commands.add_parser('toggle-hud')\n    commands.add_parser('toggle-logging')\n    commands.add_parser('start-logging')\n    commands.add_parser('stop-logging')\n    commands.add_parser('toggle-fcat')\n\n    args = parser.parse_args()\n\n    control(args)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "data/MangoHud.conf",
    "content": "### MangoHud configuration file\n### Uncomment any options you wish to enable. Default options are left uncommented\n### Use some_parameter=0 to disable a parameter (only works with on/off parameters)\n### Everything below can be used / overridden with the environment variable MANGOHUD_CONFIG instead\n\n################ INFORMATIONAL #################\n## prints possible options on stdout\n# help\n\n################ PERFORMANCE #################\n\n### Limit the application FPS. Comma-separated list of one or more FPS values (e.g. 0,30,60). 0 means unlimited (unless VSynced)\n# fps_limit=0\n\n### early = wait before present, late = wait after present\n# fps_limit_method=\n\n### Vulkan Present Mode. Overrides application present mode. Takes precedence over `vsync=`.\n# Present Modes:\n#   immediate\n#   mailbox\n#   fifo\n#   fifo_relaxed\n#   shared_demand_refresh\n#   shared_continuous_refresh\n#   fifo_latest_ready\n# Present Modes Documentation:\n#   https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html\n# vulkan_present_mode=mailbox\n\n### VSync [0-3] 0 = adaptive; 1 = off; 2 = mailbox; 3 = on\n# vsync=-1\n\n### OpenGL VSync [0-N] 0 = off; >=1 = wait for N v-blanks, N > 1 acts as a FPS limiter (FPS = display refresh rate / N)\n# gl_vsync=-2\n\n### Mip-map LoD bias. Negative values will increase texture sharpness (and aliasing)\n## Positive values will increase texture blurriness (-16 to 16)\n# picmip=-17\n\n### Anisotropic filtering level. Improves sharpness of textures viewed at an angle (0 to 16)\n# af=-1\n\n### Force bicubic filtering\n# bicubic\n\n### Force trilinear filtering\n# trilinear\n\n### Disable linear texture filtering. Makes textures look blocky\n# retro\n\n################### VISUAL ###################\n\n### Legacy layout\n# legacy_layout=0\n\n### pre defined presets\n# -1 = default\n#  0 = no display\n#  1 = fps only\n#  2 = horizontal view\n#  3 = extended\n#  4 = high detailed information\n# preset=-1\n\n### Enable most of the toggleable parameters (currently excludes `histogram`)\n# full\n\n### Show FPS only. ***Not meant to be used with other display params***\n# fps_only\n\n### Display custom centered text, useful for a header\n# custom_text_center=\n\n### Display the current system time\n# time\n## removes the time label\n# time_no_label\n\n### Time formatting examples\n## %H:%M\n## [ %T %F ]\n## %X # locally formatted time, because of limited glyph range, missing characters may show as '?' (e.g. Japanese)\n# time_format=\"%T\"\n\n### Display MangoHud version\n# version\n\n### Display the current GPU information\n## Note: gpu_mem_clock and gpu_mem_temp also need \"vram\" to be enabled\ngpu_stats\n# gpu_temp\n# gpu_junction_temp\n# gpu_core_clock\n# gpu_mem_temp\n# gpu_mem_clock\n# gpu_power\n# gpu_power_limit\n# gpu_text=\n# gpu_load_change\n# gpu_load_value=60,90\n# gpu_load_color=39F900,FDFD09,B22222\n## GPU fan in rpm on AMD, FAN in percent on NVIDIA\n# gpu_fan\n## gpu_voltage only works on AMD GPUs\n# gpu_voltage\n## Select list of GPUs to display\n# gpu_list=0,1\n# gpu_efficiency\n\n### Display the current CPU information\ncpu_stats\n# cpu_temp\n# cpu_power\n# cpu_text=\n# cpu_mhz\n# cpu_load_change\n# cpu_load_value=60,90\n# cpu_load_color=39F900,FDFD09,B22222\n# cpu_efficiency\n\n### Display the current CPU load & frequency for each core\n# core_load\n# core_load_change\n# core_bars\n# core_type\n\n### Display IO read and write for the app (not system)\n# io_read\n# io_write\n\n### Display system vram / ram / swap space usage\n# vram\n# ram\n# swap\n\n### Display per process memory usage\n## Show resident memory and other types, if enabled\n# procmem\n# procmem_shared\n# procmem_virt\n# proc_vram\n\n### Display battery information\n# battery\n# battery_icon\n# device_battery=gamepad,mouse\n# device_battery_icon\n# battery_watt\n# battery_time\n\n### Display FPS and frametime\nfps\n# fps_sampling_period=500\n# fps_color_change\n# fps_value=30,60\n# fps_color=B22222,FDFD09,39F900\n# fps_text=\"\"\nframetime\n# frame_count\n## fps_metrics takes a list of decimal values or the value avg\n# fps_metrics=avg,0.01\n\n### Display GPU throttling status based on Power, current, temp or \"other\"\n## Only shows if throttling is currently happening\nthrottling_status\n## Same as throttling_status but displays throttling on the frametime graph\n#throttling_status_graph\n\n### Display miscellaneous information\n# engine_version\n# engine_short_names\n# gpu_name\n# vulkan_driver\n# wine\n# exec_name\n# winesync\n# present_mode\n\n### Display loaded MangoHud architecture\n# arch\n\n### Display the frametime line graph\nframe_timing\n# frame_timing_detailed\n# dynamic_frame_timing\n# histogram\n\n### Display GameMode / vkBasalt running status\n# gamemode\n# vkbasalt\n\n### Gamescope related options\n## Display the status of FSR (only works in gamescope)\n# fsr\n## Hides the sharpness info for the `fsr` option (only available in gamescope)\n# hide_fsr_sharpness\n## Shows the graph of gamescope app frametimes and latency (only on gamescope obviously)\n# debug\n## Display the status of HDR (only works in gamescope)\n# hdr\n## Display the current refresh rate (only works in gamescope)\n# refresh_rate\n\n\n### graphs displays one or more graphs that you chose\n## separated by \",\", available graphs are\n## gpu_load,cpu_load,gpu_core_clock,gpu_mem_clock,vram,ram,cpu_temp,gpu_temp\n# graphs=\n\n### mangoapp related options\n## Enables mangoapp to be displayed above the Steam UI\n# mangoapp_steam\n\n### Steam Deck options\n## Shows the Steam Deck fan rpm\n# fan\n\n### Display current FPS limit\n# show_fps_limit\n\n### Display the current resolution\n# resolution\n\n### Display current display session\n# display_server\n\n### Display temperature in fahrenheit\n# temp_fahrenheit\n\n## Display efficiency in joules per frame\n# flip_efficiency\n\n### Display custom text\n# custom_text=\n### Display output of Bash command in next column\n# exec=\n\n### Display media player metadata\n# media_player\n## for example spotify\n# media_player_name=\n## Format metadata, lines are delimited by ; (wip)\n## example: {title};{artist};{album}\n## example: Track:;{title};By:;{artist};From:;{album}\n# media_player_format=title,artist,album\n\n### Network interface throughput\n# network\n## Network can take arguments but it's not required.\n## without arguments it shows all interfaces\n## arguments set which interfaces will be displayed\n# network=eth0,wlo1\n\n\n### Change the hud font size\n# font_size=24\n# font_scale=1.0\n# font_size_text=24\n# font_scale_media_player=0.55\n# no_small_font\n\n### Change default font (set location to TTF/OTF file)\n## Set font for the whole hud\n# font_file=\n\n## Set font only for text like media player metadata\n# font_file_text=\n\n## Set font glyph ranges. Defaults to Latin-only. Don't forget to set font_file/font_file_text to font that supports these\n## Probably don't enable all at once because of memory usage and hardware limits concerns\n## If you experience crashes or text is just squares, reduce glyph range or reduce font size\n# font_glyph_ranges=korean,chinese,chinese_simplified,japanese,cyrillic,thai,vietnamese,latin_ext_a,latin_ext_b\n\n### Outline text\ntext_outline\n# text_outline_color = 000000\n# text_outline_thickness = 1.5\n\n### Change the hud position\n# position=top-left\n\n### Change the corner roundness\n# round_corners=0\n\n### Remove margins around MangoHud\n# hud_no_margin\n\n### Display compact version of MangoHud\n# hud_compact\n\n### Display MangoHud in a horizontal position\n# horizontal\n# horizontal_stretch\n\n### Disable / hide the hud by default\n# no_display\n\n### Show FEX-Emu statistics\n## Only useful for Arm64 devices running applications under emulation\n# fex_stats\n\n### Hud position offset\n# offset_x=0\n# offset_y=0\n\n### Hud dimensions\n# width=0\n# height=140\n# table_columns=3\n# cellpadding_y=-0.085\n\n### Hud transparency / alpha\n# background_alpha=0.5\n# alpha=1.0\n\n### FCAT overlay\n### This enables an FCAT overlay to perform frametime analysis on the final image stream.\n### Enable the overlay\n# fcat\n### Set the width of the FCAT overlay.\n### 24 is a performance optimization on AMD GPUs that should not have adverse effects on nVidia GPUs.\n### A minimum of 20 pixels is recommended by nVidia.\n# fcat_overlay_width=24\n### Set the screen edge, this can be useful for special displays that don't update from top edge to bottom. This goes from 0 (left side) to 3 (top edge), counter-clockwise.\n# fcat_screen_edge=0\n\n### Color customization\n# text_color=FFFFFF\n# gpu_color=2E9762\n# cpu_color=2E97CB\n# vram_color=AD64C1\n# ram_color=C26693\n# engine_color=EB5B5B\n# io_color=A491D3\n# frametime_color=00FF00\n# background_color=020202\n# media_player_color=FFFFFF\n# wine_color=EB5B5B\n# battery_color=FF9078\n# network_color=E07B85\n# horizontal_separator_color=AD64C1\n\n### Specify GPU with PCI bus ID\n### Set to 'domain:bus:slot.function'\n### Example:\n###     $ lspci | grep A770\n###     03:00.0 VGA compatible controller: Intel Corporation DG2 [Arc A770] (rev 08)\n# pci_dev=0000:03:00.0\n\n### Blacklist\n# blacklist=\n\n### Control over socket\n### Enable and set socket name, '%p' is replaced with process id\n## example: mangohud\n## example: mangohud-%p\n# control = -1\n\n### ftrace tracepoint display\n## Enable display of tracepoint information gathered from ftrace. MangoHud will parse\n## out the necessary data from the ftrace pipe, ftrace itself still has to be configured\n## manually (enabling the desired event, applying any filtering etc.). The user running\n## MangoHud will require permission to access the default-mounted tracefs (expected at\n## /sys/kernel/tracing/).\n##\n## When parsing ftrace output, currently only the `key=value` format for event fields is\n## expected. This is the most common format used in events, but it's not standardized.\n##\n## Three types of display are available:\n## - `histogram/drm_vblank_event`, a histogram of event occurrence\n## - `linegraph/devfreq_monitor/freq`, a line graph of an event field's numerical value\n## - `label/devfreq_frequency/dev_name`, a textual presentation of an event field's value\n##\n## The displays are set through the `ftrace` option. Multiple displays can be specified.\n# ftrace=histogram/drm_vblank_event+linegraph/devfreq_monitor/freq\n\n################ WORKAROUNDS #################\n### Options starting with \"gl_*\" are for OpenGL\n### Specify what to use for getting display size. Options are \"viewport\", \"scissorbox\" or disabled. Defaults to using glXQueryDrawable\n# gl_size_query=viewport\n\n### (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III\n# gl_bind_framebuffer=0\n\n### Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx\n# gl_dont_flip=1\n\n################ INTERACTION #################\n\n### Change toggle keybinds for the hud & logging\n# toggle_hud=Shift_R+F12\n# toggle_hud_position=Shift_R+F11\n# toggle_preset=Shift_R+F10\n# toggle_fps_limit=Shift_L+F1\n# toggle_logging=Shift_L+F2\n# reload_cfg=Shift_L+F4\n# upload_log=Shift_L+F3\n# reset_fps_metrics=Shift_R+f9\n\n#################### LOG #####################\n### Automatically start the log after X seconds\n# autostart_log=\n### Set amount of time in seconds that the logging will run for\n# log_duration=\n### Change the default log interval, 0 is default\n# log_interval=0\n### Set location of the output files (required for logging)\n# output_folder=/home/<USERNAME>/mangologs\n### Permit uploading logs directly to FlightlessMango.com\n## set to 1 to enable\n# permit_upload=0\n### Define a '+'-separated list of percentiles shown in the benchmark results\n### Use \"AVG\" to get a mean average. Default percentiles are 97+AVG+1+0.1\n## example: ['97', 'AVG', '1', '0.1']\n# benchmark_percentiles=97,AVG\n## Adds more headers and information such as versioning to the log. This format is not supported on flightlessmango.com (yet)\n# log_versioning\n## Enable automatic uploads of logs to flightlessmango.com\n# upload_logs\n# output_file=\"\"\n"
  },
  {
    "path": "data/io.github.flightlessmango.mangohud.metainfo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"generic\">\n  <id>io.github.flightlessmango.mangohud</id>\n\n  <name>MangoHud</name>\n  <summary>Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more</summary>\n  <developer_name>FlightlessMango</developer_name>\n  <icon type=\"stock\">io.github.flightlessmango.mangohud</icon>\n\n  <metadata_license>CC0-1.0</metadata_license>\n  <project_license>MIT</project_license>\n\n  <description>\n    <p>A modification of the Mesa Vulkan overlay, including GUI improvements with HUD configuration, temperature reporting, and logging capabilities. Includes a script (mangohud) to start it on any OpenGL or Vulkan application.</p>\n  </description>\n\n  <screenshots>\n    <screenshot type=\"default\">\n      <caption>Example</caption>\n      <image>https://raw.githubusercontent.com/flightlessmango/MangoHud/master/assets/overlay_example.gif</image>\n    </screenshot>\n    <screenshot>\n      <caption>Log uploading walkthrough</caption>\n      <image>https://raw.githubusercontent.com/flightlessmango/MangoHud/master/assets/log_upload_example.gif</image>\n    </screenshot>\n  </screenshots>\n\n  <url type=\"homepage\">https://github.com/flightlessmango/MangoHud</url>\n  <url type=\"bugtracker\">https://github.com/flightlessmango/MangoHud/issues</url>\n  <url type=\"donation\">https://www.paypal.me/flightlessmango</url>\n\n  <provides>\n    <binary>mangohud</binary>\n  </provides>\n\n  <categories>\n    <category>Utility</category>\n    <category>Game</category>\n  </categories>\n\n  <content_rating type=\"oars-1.1\" />\n</component>\n"
  },
  {
    "path": "data/mangoapp.1",
    "content": ".\\\" Manpage for mangoapp.\n.TH mangoapp 1 \"\" \"\" \"mangoapp\"\n\n.SH NAME\nmangoapp \\- transparent background application with a built in mangohud\n\n.SH SYNOPSIS\n\\fBmangoapp\\fR\n\n.SH DESCRIPTION\nMangoHud is a Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more.\n.PP\nMangoapp is a transparent background opengl application with a built in MangoHud. It's designed to be run inside a\ngamescope instance which will display mangoapp ontop of gamescopes output. It also takes frame information from\ngamescope. The purpose of this is to \"easily\" make MangoHud compatible with any application, or at least any\napplication that gamescope can run. This solves issues with some OpenGL games and certain ports that have stdc++ issues\nas it's no longer directly injected into the game.\n\n.SH USAGE\nCreate a script (e.g. \\fBrun.sh\\fR) containing the app you want to run (e.g. \\fBvkcube\\fR) and \\fBmangoapp\\fR like so:\n.PP\n.RS 4\n.EX\n#!/bin/sh\n\nvkcube&\nmangoapp\n.EE\n.RE\n.PP\nAnd then run it with \\fBgamescope ./run.sh\\fR.\n\n.SH SEE ALSO\nmangohud(1)\n\n.SH ABOUT\nMangoHud development takes place at \\fIhttps://github.com/flightlessmango/MangoHud\\fR.\n.br\nBenchmarks created with MangoHud can be uploaded to \\fIhttps://flightlessmango.com\\fR.\n"
  },
  {
    "path": "data/mangohud.1",
    "content": ".\\\" Manpage for mangohud.\n.TH mangohud 1 \"\" \"\" \"mangohud\"\n\n.SH NAME\nmangohud \\- enable MangoHud on any application\n\n.SH SYNOPSIS\n\\fBmangohud\\fR [--dlsym] COMMAND\n\n.SH DESCRIPTION\nMangoHud is a Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more.\n\n.SH USAGE\nMangoHud can be enabled for Vulkan applications by setting \\fBMANGOHUD=1\\fR as environment variable.\n.br\nTo load MangoHud for any application, including OpenGL applications, the \\fBmangohud\\fR executable can be used. It preloads a library via ld into the application.\n.br\nNote: some OpenGL applications may also need dlsym hooking. This can be done by passing option \\fB--dlsym\\fR or by setting \\fBMANGOHUD_DLSYM=1\\fR as environment variable.\n\n.SH CONFIG\nMangoHud comes with a config file which can be used to set configuration options globally or per application. The priorities of different config files are:\n.LP\n.RS 4\n/path/to/application/MangoHud.conf\n.br\n$XDG_CONFIG_HOME/MangoHud/{application_name}.conf\n.br\n$XDG_CONFIG_HOME/MangoHud/MangoHud.conf\n.RS -4\n.LP\nAn example config file is located in /usr/share/doc/mangohud/MangoHud.conf, containing all available options.\n.LP\nA custom config file location can also be specified with the \\fBMANGOHUD_CONFIGFILE\\fR environment variable.\n.br\nConfig options can also be set with the \\fBMANGOHUD_CONFIG\\fR environment variable. This takes priority over any config file.\n\n.SH EXAMPLES\nOpenGL: \\fBmangohud glxgears\\fR\n.br\nVulkan: \\fBMANGOHUD=1 vkcube\\fR\n.br\nSteam: set your launch option to \\fBmangohud %command%\\fR\n.br\nLutris: add \\fBmangohud\\fR to the Command prefix setting\n.br\nOpenGL with dlsym: \\fBmangohud --dlsym glxgears\\fR\n.br\nCustom config options: \\fBMANGOHUD_CONFIG=\"gpu_stats=0,font_size=12\" mangohud glxgears\\fR\n\n.SH ABOUT\nMangoHud development takes place at \\fIhttps://github.com/flightlessmango/MangoHud\\fR.\n.br\nBenchmarks created with MangoHud can be uploaded to \\fIhttps://flightlessmango.com\\fR.\n"
  },
  {
    "path": "data/meson.build",
    "content": "man1dir = join_paths(get_option('mandir'), 'man1')\ndatadir = get_option('datadir')\nmetainfo_file = files('io.github.flightlessmango.mangohud.metainfo.xml')\nicon_file = files('io.github.flightlessmango.mangohud.svg')\n\n# Validate metainfo file\nascli_exe = find_program('appstreamcli', required: get_option('tests'))\nif ascli_exe.found()\n  test('validate metainfo file',\n       ascli_exe,\n       args: ['validate',\n              '--no-net',\n              '--pedantic',\n              metainfo_file]\n  )\nendif\n\n# Install metainfo file\ninstall_data(\n  metainfo_file,\n  install_dir: join_paths(datadir, 'metainfo'),\n  install_tag : 'doc',\n)\n\n# Install icon for metainfo\ninstall_data(\n  icon_file,\n  install_dir: join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps'),\n  install_tag : 'doc',\n)\n\n# Install man pages\ninstall_man(\n  files('mangohud.1'),\n  install_dir: man1dir,\n)\nif get_option('mangoapp')\n  install_man(\n    files('mangoapp.1'),\n    install_dir: man1dir,\n  )\nendif\n\ninstall_data(\n  files('MangoHud.conf'),\n  install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'),\n  rename : ['MangoHud.conf.example'],\n  install_tag : 'doc',\n)\n\ninstall_data(\n  files('presets.conf'),\n  install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'),\n  rename : ['presets.conf.example'],\n  install_tag : 'doc',\n)\n"
  },
  {
    "path": "data/presets.conf",
    "content": "[preset 1]\nno_display\n\n[preset 2]\nlegacy_layout=0\ncpu_stats=0\ngpu_stats=0\nfps\nfps_only=1\nframetime=0\n"
  },
  {
    "path": "include/.editorconfig",
    "content": "# ignore this folder\nroot = true\n\n"
  },
  {
    "path": "include/IconsForkAwesome.h",
    "content": "// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++\n// from https://raw.githubusercontent.com/ForkAwesome/Fork-Awesome/master/src/icons/icons.yml\n// for use with https://github.com/ForkAwesome/Fork-Awesome/blob/master/fonts/forkawesome-webfont.ttf\n#pragma once\n\n#define FONT_ICON_FILE_NAME_FK \"forkawesome-webfont.ttf\"\n\n#define ICON_MIN_FK 0xf000\n#define ICON_MAX_FK 0xf35f\n#define ICON_FK_GLASS \"\\xef\\x80\\x80\"\t// U+f000\n#define ICON_FK_MUSIC \"\\xef\\x80\\x81\"\t// U+f001\n#define ICON_FK_SEARCH \"\\xef\\x80\\x82\"\t// U+f002\n#define ICON_FK_ENVELOPE_O \"\\xef\\x80\\x83\"\t// U+f003\n#define ICON_FK_HEART \"\\xef\\x80\\x84\"\t// U+f004\n#define ICON_FK_STAR \"\\xef\\x80\\x85\"\t// U+f005\n#define ICON_FK_STAR_O \"\\xef\\x80\\x86\"\t// U+f006\n#define ICON_FK_USER \"\\xef\\x80\\x87\"\t// U+f007\n#define ICON_FK_FILM \"\\xef\\x80\\x88\"\t// U+f008\n#define ICON_FK_TH_LARGE \"\\xef\\x80\\x89\"\t// U+f009\n#define ICON_FK_TH \"\\xef\\x80\\x8a\"\t// U+f00a\n#define ICON_FK_TH_LIST \"\\xef\\x80\\x8b\"\t// U+f00b\n#define ICON_FK_CHECK \"\\xef\\x80\\x8c\"\t// U+f00c\n#define ICON_FK_TIMES \"\\xef\\x80\\x8d\"\t// U+f00d\n#define ICON_FK_SEARCH_PLUS \"\\xef\\x80\\x8e\"\t// U+f00e\n#define ICON_FK_SEARCH_MINUS \"\\xef\\x80\\x90\"\t// U+f010\n#define ICON_FK_POWER_OFF \"\\xef\\x80\\x91\"\t// U+f011\n#define ICON_FK_SIGNAL \"\\xef\\x80\\x92\"\t// U+f012\n#define ICON_FK_COG \"\\xef\\x80\\x93\"\t// U+f013\n#define ICON_FK_TRASH_O \"\\xef\\x80\\x94\"\t// U+f014\n#define ICON_FK_HOME \"\\xef\\x80\\x95\"\t// U+f015\n#define ICON_FK_FILE_O \"\\xef\\x80\\x96\"\t// U+f016\n#define ICON_FK_CLOCK_O \"\\xef\\x80\\x97\"\t// U+f017\n#define ICON_FK_ROAD \"\\xef\\x80\\x98\"\t// U+f018\n#define ICON_FK_DOWNLOAD \"\\xef\\x80\\x99\"\t// U+f019\n#define ICON_FK_ARROW_CIRCLE_O_DOWN \"\\xef\\x80\\x9a\"\t// U+f01a\n#define ICON_FK_ARROW_CIRCLE_O_UP \"\\xef\\x80\\x9b\"\t// U+f01b\n#define ICON_FK_INBOX \"\\xef\\x80\\x9c\"\t// U+f01c\n#define ICON_FK_PLAY_CIRCLE_O \"\\xef\\x80\\x9d\"\t// U+f01d\n#define ICON_FK_REPEAT \"\\xef\\x80\\x9e\"\t// U+f01e\n#define ICON_FK_REFRESH \"\\xef\\x80\\xa1\"\t// U+f021\n#define ICON_FK_LIST_ALT \"\\xef\\x80\\xa2\"\t// U+f022\n#define ICON_FK_LOCK \"\\xef\\x80\\xa3\"\t// U+f023\n#define ICON_FK_FLAG \"\\xef\\x80\\xa4\"\t// U+f024\n#define ICON_FK_HEADPHONES \"\\xef\\x80\\xa5\"\t// U+f025\n#define ICON_FK_VOLUME_OFF \"\\xef\\x80\\xa6\"\t// U+f026\n#define ICON_FK_VOLUME_DOWN \"\\xef\\x80\\xa7\"\t// U+f027\n#define ICON_FK_VOLUME_UP \"\\xef\\x80\\xa8\"\t// U+f028\n#define ICON_FK_QRCODE \"\\xef\\x80\\xa9\"\t// U+f029\n#define ICON_FK_BARCODE \"\\xef\\x80\\xaa\"\t// U+f02a\n#define ICON_FK_TAG \"\\xef\\x80\\xab\"\t// U+f02b\n#define ICON_FK_TAGS \"\\xef\\x80\\xac\"\t// U+f02c\n#define ICON_FK_BOOK \"\\xef\\x80\\xad\"\t// U+f02d\n#define ICON_FK_BOOKMARK \"\\xef\\x80\\xae\"\t// U+f02e\n#define ICON_FK_PRINT \"\\xef\\x80\\xaf\"\t// U+f02f\n#define ICON_FK_CAMERA \"\\xef\\x80\\xb0\"\t// U+f030\n#define ICON_FK_FONT \"\\xef\\x80\\xb1\"\t// U+f031\n#define ICON_FK_BOLD \"\\xef\\x80\\xb2\"\t// U+f032\n#define ICON_FK_ITALIC \"\\xef\\x80\\xb3\"\t// U+f033\n#define ICON_FK_TEXT_HEIGHT \"\\xef\\x80\\xb4\"\t// U+f034\n#define ICON_FK_TEXT_WIDTH \"\\xef\\x80\\xb5\"\t// U+f035\n#define ICON_FK_ALIGN_LEFT \"\\xef\\x80\\xb6\"\t// U+f036\n#define ICON_FK_ALIGN_CENTER \"\\xef\\x80\\xb7\"\t// U+f037\n#define ICON_FK_ALIGN_RIGHT \"\\xef\\x80\\xb8\"\t// U+f038\n#define ICON_FK_ALIGN_JUSTIFY \"\\xef\\x80\\xb9\"\t// U+f039\n#define ICON_FK_LIST \"\\xef\\x80\\xba\"\t// U+f03a\n#define ICON_FK_OUTDENT \"\\xef\\x80\\xbb\"\t// U+f03b\n#define ICON_FK_INDENT \"\\xef\\x80\\xbc\"\t// U+f03c\n#define ICON_FK_VIDEO_CAMERA \"\\xef\\x80\\xbd\"\t// U+f03d\n#define ICON_FK_PICTURE_O \"\\xef\\x80\\xbe\"\t// U+f03e\n#define ICON_FK_PENCIL \"\\xef\\x81\\x80\"\t// U+f040\n#define ICON_FK_MAP_MARKER \"\\xef\\x81\\x81\"\t// U+f041\n#define ICON_FK_ADJUST \"\\xef\\x81\\x82\"\t// U+f042\n#define ICON_FK_TINT \"\\xef\\x81\\x83\"\t// U+f043\n#define ICON_FK_PENCIL_SQUARE_O \"\\xef\\x81\\x84\"\t// U+f044\n#define ICON_FK_SHARE_SQUARE_O \"\\xef\\x81\\x85\"\t// U+f045\n#define ICON_FK_CHECK_SQUARE_O \"\\xef\\x81\\x86\"\t// U+f046\n#define ICON_FK_ARROWS \"\\xef\\x81\\x87\"\t// U+f047\n#define ICON_FK_STEP_BACKWARD \"\\xef\\x81\\x88\"\t// U+f048\n#define ICON_FK_FAST_BACKWARD \"\\xef\\x81\\x89\"\t// U+f049\n#define ICON_FK_BACKWARD \"\\xef\\x81\\x8a\"\t// U+f04a\n#define ICON_FK_PLAY \"\\xef\\x81\\x8b\"\t// U+f04b\n#define ICON_FK_PAUSE \"\\xef\\x81\\x8c\"\t// U+f04c\n#define ICON_FK_STOP \"\\xef\\x81\\x8d\"\t// U+f04d\n#define ICON_FK_FORWARD \"\\xef\\x81\\x8e\"\t// U+f04e\n#define ICON_FK_FAST_FORWARD \"\\xef\\x81\\x90\"\t// U+f050\n#define ICON_FK_STEP_FORWARD \"\\xef\\x81\\x91\"\t// U+f051\n#define ICON_FK_EJECT \"\\xef\\x81\\x92\"\t// U+f052\n#define ICON_FK_CHEVRON_LEFT \"\\xef\\x81\\x93\"\t// U+f053\n#define ICON_FK_CHEVRON_RIGHT \"\\xef\\x81\\x94\"\t// U+f054\n#define ICON_FK_PLUS_CIRCLE \"\\xef\\x81\\x95\"\t// U+f055\n#define ICON_FK_MINUS_CIRCLE \"\\xef\\x81\\x96\"\t// U+f056\n#define ICON_FK_TIMES_CIRCLE \"\\xef\\x81\\x97\"\t// U+f057\n#define ICON_FK_CHECK_CIRCLE \"\\xef\\x81\\x98\"\t// U+f058\n#define ICON_FK_QUESTION_CIRCLE \"\\xef\\x81\\x99\"\t// U+f059\n#define ICON_FK_INFO_CIRCLE \"\\xef\\x81\\x9a\"\t// U+f05a\n#define ICON_FK_CROSSHAIRS \"\\xef\\x81\\x9b\"\t// U+f05b\n#define ICON_FK_TIMES_CIRCLE_O \"\\xef\\x81\\x9c\"\t// U+f05c\n#define ICON_FK_CHECK_CIRCLE_O \"\\xef\\x81\\x9d\"\t// U+f05d\n#define ICON_FK_BAN \"\\xef\\x81\\x9e\"\t// U+f05e\n#define ICON_FK_ARROW_LEFT \"\\xef\\x81\\xa0\"\t// U+f060\n#define ICON_FK_ARROW_RIGHT \"\\xef\\x81\\xa1\"\t// U+f061\n#define ICON_FK_ARROW_UP \"\\xef\\x81\\xa2\"\t// U+f062\n#define ICON_FK_ARROW_DOWN \"\\xef\\x81\\xa3\"\t// U+f063\n#define ICON_FK_SHARE \"\\xef\\x81\\xa4\"\t// U+f064\n#define ICON_FK_EXPAND \"\\xef\\x81\\xa5\"\t// U+f065\n#define ICON_FK_COMPRESS \"\\xef\\x81\\xa6\"\t// U+f066\n#define ICON_FK_PLUS \"\\xef\\x81\\xa7\"\t// U+f067\n#define ICON_FK_MINUS \"\\xef\\x81\\xa8\"\t// U+f068\n#define ICON_FK_ASTERISK \"\\xef\\x81\\xa9\"\t// U+f069\n#define ICON_FK_EXCLAMATION_CIRCLE \"\\xef\\x81\\xaa\"\t// U+f06a\n#define ICON_FK_GIFT \"\\xef\\x81\\xab\"\t// U+f06b\n#define ICON_FK_LEAF \"\\xef\\x81\\xac\"\t// U+f06c\n#define ICON_FK_FIRE \"\\xef\\x81\\xad\"\t// U+f06d\n#define ICON_FK_EYE \"\\xef\\x81\\xae\"\t// U+f06e\n#define ICON_FK_EYE_SLASH \"\\xef\\x81\\xb0\"\t// U+f070\n#define ICON_FK_EXCLAMATION_TRIANGLE \"\\xef\\x81\\xb1\"\t// U+f071\n#define ICON_FK_PLANE \"\\xef\\x81\\xb2\"\t// U+f072\n#define ICON_FK_CALENDAR \"\\xef\\x81\\xb3\"\t// U+f073\n#define ICON_FK_RANDOM \"\\xef\\x81\\xb4\"\t// U+f074\n#define ICON_FK_COMMENT \"\\xef\\x81\\xb5\"\t// U+f075\n#define ICON_FK_MAGNET \"\\xef\\x81\\xb6\"\t// U+f076\n#define ICON_FK_CHEVRON_UP \"\\xef\\x81\\xb7\"\t// U+f077\n#define ICON_FK_CHEVRON_DOWN \"\\xef\\x81\\xb8\"\t// U+f078\n#define ICON_FK_RETWEET \"\\xef\\x81\\xb9\"\t// U+f079\n#define ICON_FK_SHOPPING_CART \"\\xef\\x81\\xba\"\t// U+f07a\n#define ICON_FK_FOLDER \"\\xef\\x81\\xbb\"\t// U+f07b\n#define ICON_FK_FOLDER_OPEN \"\\xef\\x81\\xbc\"\t// U+f07c\n#define ICON_FK_ARROWS_V \"\\xef\\x81\\xbd\"\t// U+f07d\n#define ICON_FK_ARROWS_H \"\\xef\\x81\\xbe\"\t// U+f07e\n#define ICON_FK_BAR_CHART \"\\xef\\x82\\x80\"\t// U+f080\n#define ICON_FK_TWITTER_SQUARE \"\\xef\\x82\\x81\"\t// U+f081\n#define ICON_FK_FACEBOOK_SQUARE \"\\xef\\x82\\x82\"\t// U+f082\n#define ICON_FK_CAMERA_RETRO \"\\xef\\x82\\x83\"\t// U+f083\n#define ICON_FK_KEY \"\\xef\\x82\\x84\"\t// U+f084\n#define ICON_FK_COGS \"\\xef\\x82\\x85\"\t// U+f085\n#define ICON_FK_COMMENTS \"\\xef\\x82\\x86\"\t// U+f086\n#define ICON_FK_THUMBS_O_UP \"\\xef\\x82\\x87\"\t// U+f087\n#define ICON_FK_THUMBS_O_DOWN \"\\xef\\x82\\x88\"\t// U+f088\n#define ICON_FK_STAR_HALF \"\\xef\\x82\\x89\"\t// U+f089\n#define ICON_FK_HEART_O \"\\xef\\x82\\x8a\"\t// U+f08a\n#define ICON_FK_SIGN_OUT \"\\xef\\x82\\x8b\"\t// U+f08b\n#define ICON_FK_LINKEDIN_SQUARE \"\\xef\\x82\\x8c\"\t// U+f08c\n#define ICON_FK_THUMB_TACK \"\\xef\\x82\\x8d\"\t// U+f08d\n#define ICON_FK_EXTERNAL_LINK \"\\xef\\x82\\x8e\"\t// U+f08e\n#define ICON_FK_SIGN_IN \"\\xef\\x82\\x90\"\t// U+f090\n#define ICON_FK_TROPHY \"\\xef\\x82\\x91\"\t// U+f091\n#define ICON_FK_GITHUB_SQUARE \"\\xef\\x82\\x92\"\t// U+f092\n#define ICON_FK_UPLOAD \"\\xef\\x82\\x93\"\t// U+f093\n#define ICON_FK_LEMON_O \"\\xef\\x82\\x94\"\t// U+f094\n#define ICON_FK_PHONE \"\\xef\\x82\\x95\"\t// U+f095\n#define ICON_FK_SQUARE_O \"\\xef\\x82\\x96\"\t// U+f096\n#define ICON_FK_BOOKMARK_O \"\\xef\\x82\\x97\"\t// U+f097\n#define ICON_FK_PHONE_SQUARE \"\\xef\\x82\\x98\"\t// U+f098\n#define ICON_FK_TWITTER \"\\xef\\x82\\x99\"\t// U+f099\n#define ICON_FK_FACEBOOK \"\\xef\\x82\\x9a\"\t// U+f09a\n#define ICON_FK_GITHUB \"\\xef\\x82\\x9b\"\t// U+f09b\n#define ICON_FK_UNLOCK \"\\xef\\x82\\x9c\"\t// U+f09c\n#define ICON_FK_CREDIT_CARD \"\\xef\\x82\\x9d\"\t// U+f09d\n#define ICON_FK_RSS \"\\xef\\x82\\x9e\"\t// U+f09e\n#define ICON_FK_HDD_O \"\\xef\\x82\\xa0\"\t// U+f0a0\n#define ICON_FK_BULLHORN \"\\xef\\x82\\xa1\"\t// U+f0a1\n#define ICON_FK_BELL_O \"\\xef\\x83\\xb3\"\t// U+f0f3\n#define ICON_FK_CERTIFICATE \"\\xef\\x82\\xa3\"\t// U+f0a3\n#define ICON_FK_HAND_O_RIGHT \"\\xef\\x82\\xa4\"\t// U+f0a4\n#define ICON_FK_HAND_O_LEFT \"\\xef\\x82\\xa5\"\t// U+f0a5\n#define ICON_FK_HAND_O_UP \"\\xef\\x82\\xa6\"\t// U+f0a6\n#define ICON_FK_HAND_O_DOWN \"\\xef\\x82\\xa7\"\t// U+f0a7\n#define ICON_FK_ARROW_CIRCLE_LEFT \"\\xef\\x82\\xa8\"\t// U+f0a8\n#define ICON_FK_ARROW_CIRCLE_RIGHT \"\\xef\\x82\\xa9\"\t// U+f0a9\n#define ICON_FK_ARROW_CIRCLE_UP \"\\xef\\x82\\xaa\"\t// U+f0aa\n#define ICON_FK_ARROW_CIRCLE_DOWN \"\\xef\\x82\\xab\"\t// U+f0ab\n#define ICON_FK_GLOBE \"\\xef\\x82\\xac\"\t// U+f0ac\n#define ICON_FK_GLOBE_E \"\\xef\\x8c\\x84\"\t// U+f304\n#define ICON_FK_GLOBE_W \"\\xef\\x8c\\x85\"\t// U+f305\n#define ICON_FK_WRENCH \"\\xef\\x82\\xad\"\t// U+f0ad\n#define ICON_FK_TASKS \"\\xef\\x82\\xae\"\t// U+f0ae\n#define ICON_FK_FILTER \"\\xef\\x82\\xb0\"\t// U+f0b0\n#define ICON_FK_BRIEFCASE \"\\xef\\x82\\xb1\"\t// U+f0b1\n#define ICON_FK_ARROWS_ALT \"\\xef\\x82\\xb2\"\t// U+f0b2\n#define ICON_FK_USERS \"\\xef\\x83\\x80\"\t// U+f0c0\n#define ICON_FK_LINK \"\\xef\\x83\\x81\"\t// U+f0c1\n#define ICON_FK_CLOUD \"\\xef\\x83\\x82\"\t// U+f0c2\n#define ICON_FK_FLASK \"\\xef\\x83\\x83\"\t// U+f0c3\n#define ICON_FK_SCISSORS \"\\xef\\x83\\x84\"\t// U+f0c4\n#define ICON_FK_FILES_O \"\\xef\\x83\\x85\"\t// U+f0c5\n#define ICON_FK_PAPERCLIP \"\\xef\\x83\\x86\"\t// U+f0c6\n#define ICON_FK_FLOPPY_O \"\\xef\\x83\\x87\"\t// U+f0c7\n#define ICON_FK_SQUARE \"\\xef\\x83\\x88\"\t// U+f0c8\n#define ICON_FK_BARS \"\\xef\\x83\\x89\"\t// U+f0c9\n#define ICON_FK_LIST_UL \"\\xef\\x83\\x8a\"\t// U+f0ca\n#define ICON_FK_LIST_OL \"\\xef\\x83\\x8b\"\t// U+f0cb\n#define ICON_FK_STRIKETHROUGH \"\\xef\\x83\\x8c\"\t// U+f0cc\n#define ICON_FK_UNDERLINE \"\\xef\\x83\\x8d\"\t// U+f0cd\n#define ICON_FK_TABLE \"\\xef\\x83\\x8e\"\t// U+f0ce\n#define ICON_FK_MAGIC \"\\xef\\x83\\x90\"\t// U+f0d0\n#define ICON_FK_TRUCK \"\\xef\\x83\\x91\"\t// U+f0d1\n#define ICON_FK_PINTEREST \"\\xef\\x83\\x92\"\t// U+f0d2\n#define ICON_FK_PINTEREST_SQUARE \"\\xef\\x83\\x93\"\t// U+f0d3\n#define ICON_FK_GOOGLE_PLUS_SQUARE \"\\xef\\x83\\x94\"\t// U+f0d4\n#define ICON_FK_GOOGLE_PLUS \"\\xef\\x83\\x95\"\t// U+f0d5\n#define ICON_FK_MONEY \"\\xef\\x83\\x96\"\t// U+f0d6\n#define ICON_FK_CARET_DOWN \"\\xef\\x83\\x97\"\t// U+f0d7\n#define ICON_FK_CARET_UP \"\\xef\\x83\\x98\"\t// U+f0d8\n#define ICON_FK_CARET_LEFT \"\\xef\\x83\\x99\"\t// U+f0d9\n#define ICON_FK_CARET_RIGHT \"\\xef\\x83\\x9a\"\t// U+f0da\n#define ICON_FK_COLUMNS \"\\xef\\x83\\x9b\"\t// U+f0db\n#define ICON_FK_SORT \"\\xef\\x83\\x9c\"\t// U+f0dc\n#define ICON_FK_SORT_DESC \"\\xef\\x83\\x9d\"\t// U+f0dd\n#define ICON_FK_SORT_ASC \"\\xef\\x83\\x9e\"\t// U+f0de\n#define ICON_FK_ENVELOPE \"\\xef\\x83\\xa0\"\t// U+f0e0\n#define ICON_FK_LINKEDIN \"\\xef\\x83\\xa1\"\t// U+f0e1\n#define ICON_FK_UNDO \"\\xef\\x83\\xa2\"\t// U+f0e2\n#define ICON_FK_GAVEL \"\\xef\\x83\\xa3\"\t// U+f0e3\n#define ICON_FK_TACHOMETER \"\\xef\\x83\\xa4\"\t// U+f0e4\n#define ICON_FK_COMMENT_O \"\\xef\\x83\\xa5\"\t// U+f0e5\n#define ICON_FK_COMMENTS_O \"\\xef\\x83\\xa6\"\t// U+f0e6\n#define ICON_FK_BOLT \"\\xef\\x83\\xa7\"\t// U+f0e7\n#define ICON_FK_SITEMAP \"\\xef\\x83\\xa8\"\t// U+f0e8\n#define ICON_FK_UMBRELLA \"\\xef\\x83\\xa9\"\t// U+f0e9\n#define ICON_FK_CLIPBOARD \"\\xef\\x83\\xaa\"\t// U+f0ea\n#define ICON_FK_LIGHTBULB_O \"\\xef\\x83\\xab\"\t// U+f0eb\n#define ICON_FK_EXCHANGE \"\\xef\\x83\\xac\"\t// U+f0ec\n#define ICON_FK_CLOUD_DOWNLOAD \"\\xef\\x83\\xad\"\t// U+f0ed\n#define ICON_FK_CLOUD_UPLOAD \"\\xef\\x83\\xae\"\t// U+f0ee\n#define ICON_FK_USER_MD \"\\xef\\x83\\xb0\"\t// U+f0f0\n#define ICON_FK_STETHOSCOPE \"\\xef\\x83\\xb1\"\t// U+f0f1\n#define ICON_FK_SUITCASE \"\\xef\\x83\\xb2\"\t// U+f0f2\n#define ICON_FK_BELL \"\\xef\\x82\\xa2\"\t// U+f0a2\n#define ICON_FK_COFFEE \"\\xef\\x83\\xb4\"\t// U+f0f4\n#define ICON_FK_CUTLERY \"\\xef\\x83\\xb5\"\t// U+f0f5\n#define ICON_FK_FILE_TEXT_O \"\\xef\\x83\\xb6\"\t// U+f0f6\n#define ICON_FK_BUILDING_O \"\\xef\\x83\\xb7\"\t// U+f0f7\n#define ICON_FK_HOSPITAL_O \"\\xef\\x83\\xb8\"\t// U+f0f8\n#define ICON_FK_AMBULANCE \"\\xef\\x83\\xb9\"\t// U+f0f9\n#define ICON_FK_MEDKIT \"\\xef\\x83\\xba\"\t// U+f0fa\n#define ICON_FK_FIGHTER_JET \"\\xef\\x83\\xbb\"\t// U+f0fb\n#define ICON_FK_BEER \"\\xef\\x83\\xbc\"\t// U+f0fc\n#define ICON_FK_H_SQUARE \"\\xef\\x83\\xbd\"\t// U+f0fd\n#define ICON_FK_PLUS_SQUARE \"\\xef\\x83\\xbe\"\t// U+f0fe\n#define ICON_FK_ANGLE_DOUBLE_LEFT \"\\xef\\x84\\x80\"\t// U+f100\n#define ICON_FK_ANGLE_DOUBLE_RIGHT \"\\xef\\x84\\x81\"\t// U+f101\n#define ICON_FK_ANGLE_DOUBLE_UP \"\\xef\\x84\\x82\"\t// U+f102\n#define ICON_FK_ANGLE_DOUBLE_DOWN \"\\xef\\x84\\x83\"\t// U+f103\n#define ICON_FK_ANGLE_LEFT \"\\xef\\x84\\x84\"\t// U+f104\n#define ICON_FK_ANGLE_RIGHT \"\\xef\\x84\\x85\"\t// U+f105\n#define ICON_FK_ANGLE_UP \"\\xef\\x84\\x86\"\t// U+f106\n#define ICON_FK_ANGLE_DOWN \"\\xef\\x84\\x87\"\t// U+f107\n#define ICON_FK_DESKTOP \"\\xef\\x84\\x88\"\t// U+f108\n#define ICON_FK_LAPTOP \"\\xef\\x84\\x89\"\t// U+f109\n#define ICON_FK_TABLET \"\\xef\\x84\\x8a\"\t// U+f10a\n#define ICON_FK_MOBILE \"\\xef\\x84\\x8b\"\t// U+f10b\n#define ICON_FK_CIRCLE_O \"\\xef\\x84\\x8c\"\t// U+f10c\n#define ICON_FK_QUOTE_LEFT \"\\xef\\x84\\x8d\"\t// U+f10d\n#define ICON_FK_QUOTE_RIGHT \"\\xef\\x84\\x8e\"\t// U+f10e\n#define ICON_FK_SPINNER \"\\xef\\x84\\x90\"\t// U+f110\n#define ICON_FK_CIRCLE \"\\xef\\x84\\x91\"\t// U+f111\n#define ICON_FK_REPLY \"\\xef\\x84\\x92\"\t// U+f112\n#define ICON_FK_GITHUB_ALT \"\\xef\\x84\\x93\"\t// U+f113\n#define ICON_FK_FOLDER_O \"\\xef\\x84\\x94\"\t// U+f114\n#define ICON_FK_FOLDER_OPEN_O \"\\xef\\x84\\x95\"\t// U+f115\n#define ICON_FK_SMILE_O \"\\xef\\x84\\x98\"\t// U+f118\n#define ICON_FK_FROWN_O \"\\xef\\x84\\x99\"\t// U+f119\n#define ICON_FK_MEH_O \"\\xef\\x84\\x9a\"\t// U+f11a\n#define ICON_FK_GAMEPAD \"\\xef\\x84\\x9b\"\t// U+f11b\n#define ICON_FK_KEYBOARD_O \"\\xef\\x84\\x9c\"\t// U+f11c\n#define ICON_FK_FLAG_O \"\\xef\\x84\\x9d\"\t// U+f11d\n#define ICON_FK_FLAG_CHECKERED \"\\xef\\x84\\x9e\"\t// U+f11e\n#define ICON_FK_TERMINAL \"\\xef\\x84\\xa0\"\t// U+f120\n#define ICON_FK_CODE \"\\xef\\x84\\xa1\"\t// U+f121\n#define ICON_FK_REPLY_ALL \"\\xef\\x84\\xa2\"\t// U+f122\n#define ICON_FK_STAR_HALF_O \"\\xef\\x84\\xa3\"\t// U+f123\n#define ICON_FK_LOCATION_ARROW \"\\xef\\x84\\xa4\"\t// U+f124\n#define ICON_FK_CROP \"\\xef\\x84\\xa5\"\t// U+f125\n#define ICON_FK_CODE_FORK \"\\xef\\x84\\xa6\"\t// U+f126\n#define ICON_FK_CHAIN_BROKEN \"\\xef\\x84\\xa7\"\t// U+f127\n#define ICON_FK_QUESTION \"\\xef\\x84\\xa8\"\t// U+f128\n#define ICON_FK_INFO \"\\xef\\x84\\xa9\"\t// U+f129\n#define ICON_FK_EXCLAMATION \"\\xef\\x84\\xaa\"\t// U+f12a\n#define ICON_FK_SUPERSCRIPT \"\\xef\\x84\\xab\"\t// U+f12b\n#define ICON_FK_SUBSCRIPT \"\\xef\\x84\\xac\"\t// U+f12c\n#define ICON_FK_ERASER \"\\xef\\x84\\xad\"\t// U+f12d\n#define ICON_FK_PUZZLE_PIECE \"\\xef\\x84\\xae\"\t// U+f12e\n#define ICON_FK_MICROPHONE \"\\xef\\x84\\xb0\"\t// U+f130\n#define ICON_FK_MICROPHONE_SLASH \"\\xef\\x84\\xb1\"\t// U+f131\n#define ICON_FK_SHIELD \"\\xef\\x84\\xb2\"\t// U+f132\n#define ICON_FK_CALENDAR_O \"\\xef\\x84\\xb3\"\t// U+f133\n#define ICON_FK_FIRE_EXTINGUISHER \"\\xef\\x84\\xb4\"\t// U+f134\n#define ICON_FK_ROCKET \"\\xef\\x84\\xb5\"\t// U+f135\n#define ICON_FK_MAXCDN \"\\xef\\x84\\xb6\"\t// U+f136\n#define ICON_FK_CHEVRON_CIRCLE_LEFT \"\\xef\\x84\\xb7\"\t// U+f137\n#define ICON_FK_CHEVRON_CIRCLE_RIGHT \"\\xef\\x84\\xb8\"\t// U+f138\n#define ICON_FK_CHEVRON_CIRCLE_UP \"\\xef\\x84\\xb9\"\t// U+f139\n#define ICON_FK_CHEVRON_CIRCLE_DOWN \"\\xef\\x84\\xba\"\t// U+f13a\n#define ICON_FK_HTML5 \"\\xef\\x84\\xbb\"\t// U+f13b\n#define ICON_FK_CSS3 \"\\xef\\x84\\xbc\"\t// U+f13c\n#define ICON_FK_ANCHOR \"\\xef\\x84\\xbd\"\t// U+f13d\n#define ICON_FK_UNLOCK_ALT \"\\xef\\x84\\xbe\"\t// U+f13e\n#define ICON_FK_BULLSEYE \"\\xef\\x85\\x80\"\t// U+f140\n#define ICON_FK_ELLIPSIS_H \"\\xef\\x85\\x81\"\t// U+f141\n#define ICON_FK_ELLIPSIS_V \"\\xef\\x85\\x82\"\t// U+f142\n#define ICON_FK_RSS_SQUARE \"\\xef\\x85\\x83\"\t// U+f143\n#define ICON_FK_PLAY_CIRCLE \"\\xef\\x85\\x84\"\t// U+f144\n#define ICON_FK_TICKET \"\\xef\\x85\\x85\"\t// U+f145\n#define ICON_FK_MINUS_SQUARE \"\\xef\\x85\\x86\"\t// U+f146\n#define ICON_FK_MINUS_SQUARE_O \"\\xef\\x85\\x87\"\t// U+f147\n#define ICON_FK_LEVEL_UP \"\\xef\\x85\\x88\"\t// U+f148\n#define ICON_FK_LEVEL_DOWN \"\\xef\\x85\\x89\"\t// U+f149\n#define ICON_FK_CHECK_SQUARE \"\\xef\\x85\\x8a\"\t// U+f14a\n#define ICON_FK_PENCIL_SQUARE \"\\xef\\x85\\x8b\"\t// U+f14b\n#define ICON_FK_EXTERNAL_LINK_SQUARE \"\\xef\\x85\\x8c\"\t// U+f14c\n#define ICON_FK_SHARE_SQUARE \"\\xef\\x85\\x8d\"\t// U+f14d\n#define ICON_FK_COMPASS \"\\xef\\x85\\x8e\"\t// U+f14e\n#define ICON_FK_CARET_SQUARE_O_DOWN \"\\xef\\x85\\x90\"\t// U+f150\n#define ICON_FK_CARET_SQUARE_O_UP \"\\xef\\x85\\x91\"\t// U+f151\n#define ICON_FK_CARET_SQUARE_O_RIGHT \"\\xef\\x85\\x92\"\t// U+f152\n#define ICON_FK_EUR \"\\xef\\x85\\x93\"\t// U+f153\n#define ICON_FK_GBP \"\\xef\\x85\\x94\"\t// U+f154\n#define ICON_FK_USD \"\\xef\\x85\\x95\"\t// U+f155\n#define ICON_FK_INR \"\\xef\\x85\\x96\"\t// U+f156\n#define ICON_FK_JPY \"\\xef\\x85\\x97\"\t// U+f157\n#define ICON_FK_RUB \"\\xef\\x85\\x98\"\t// U+f158\n#define ICON_FK_KRW \"\\xef\\x85\\x99\"\t// U+f159\n#define ICON_FK_BTC \"\\xef\\x85\\x9a\"\t// U+f15a\n#define ICON_FK_FILE \"\\xef\\x85\\x9b\"\t// U+f15b\n#define ICON_FK_FILE_TEXT \"\\xef\\x85\\x9c\"\t// U+f15c\n#define ICON_FK_SORT_ALPHA_ASC \"\\xef\\x85\\x9d\"\t// U+f15d\n#define ICON_FK_SORT_ALPHA_DESC \"\\xef\\x85\\x9e\"\t// U+f15e\n#define ICON_FK_SORT_AMOUNT_ASC \"\\xef\\x85\\xa0\"\t// U+f160\n#define ICON_FK_SORT_AMOUNT_DESC \"\\xef\\x85\\xa1\"\t// U+f161\n#define ICON_FK_SORT_NUMERIC_ASC \"\\xef\\x85\\xa2\"\t// U+f162\n#define ICON_FK_SORT_NUMERIC_DESC \"\\xef\\x85\\xa3\"\t// U+f163\n#define ICON_FK_THUMBS_UP \"\\xef\\x85\\xa4\"\t// U+f164\n#define ICON_FK_THUMBS_DOWN \"\\xef\\x85\\xa5\"\t// U+f165\n#define ICON_FK_YOUTUBE_SQUARE \"\\xef\\x85\\xa6\"\t// U+f166\n#define ICON_FK_YOUTUBE \"\\xef\\x85\\xa7\"\t// U+f167\n#define ICON_FK_XING \"\\xef\\x85\\xa8\"\t// U+f168\n#define ICON_FK_XING_SQUARE \"\\xef\\x85\\xa9\"\t// U+f169\n#define ICON_FK_YOUTUBE_PLAY \"\\xef\\x85\\xaa\"\t// U+f16a\n#define ICON_FK_DROPBOX \"\\xef\\x85\\xab\"\t// U+f16b\n#define ICON_FK_STACK_OVERFLOW \"\\xef\\x85\\xac\"\t// U+f16c\n#define ICON_FK_INSTAGRAM \"\\xef\\x85\\xad\"\t// U+f16d\n#define ICON_FK_FLICKR \"\\xef\\x85\\xae\"\t// U+f16e\n#define ICON_FK_ADN \"\\xef\\x85\\xb0\"\t// U+f170\n#define ICON_FK_BITBUCKET \"\\xef\\x85\\xb1\"\t// U+f171\n#define ICON_FK_BITBUCKET_SQUARE \"\\xef\\x85\\xb2\"\t// U+f172\n#define ICON_FK_TUMBLR \"\\xef\\x85\\xb3\"\t// U+f173\n#define ICON_FK_TUMBLR_SQUARE \"\\xef\\x85\\xb4\"\t// U+f174\n#define ICON_FK_LONG_ARROW_DOWN \"\\xef\\x85\\xb5\"\t// U+f175\n#define ICON_FK_LONG_ARROW_UP \"\\xef\\x85\\xb6\"\t// U+f176\n#define ICON_FK_LONG_ARROW_LEFT \"\\xef\\x85\\xb7\"\t// U+f177\n#define ICON_FK_LONG_ARROW_RIGHT \"\\xef\\x85\\xb8\"\t// U+f178\n#define ICON_FK_APPLE \"\\xef\\x85\\xb9\"\t// U+f179\n#define ICON_FK_WINDOWS \"\\xef\\x85\\xba\"\t// U+f17a\n#define ICON_FK_ANDROID \"\\xef\\x85\\xbb\"\t// U+f17b\n#define ICON_FK_LINUX \"\\xef\\x85\\xbc\"\t// U+f17c\n#define ICON_FK_DRIBBBLE \"\\xef\\x85\\xbd\"\t// U+f17d\n#define ICON_FK_SKYPE \"\\xef\\x85\\xbe\"\t// U+f17e\n#define ICON_FK_FOURSQUARE \"\\xef\\x86\\x80\"\t// U+f180\n#define ICON_FK_TRELLO \"\\xef\\x86\\x81\"\t// U+f181\n#define ICON_FK_FEMALE \"\\xef\\x86\\x82\"\t// U+f182\n#define ICON_FK_MALE \"\\xef\\x86\\x83\"\t// U+f183\n#define ICON_FK_GRATIPAY \"\\xef\\x86\\x84\"\t// U+f184\n#define ICON_FK_SUN_O \"\\xef\\x86\\x85\"\t// U+f185\n#define ICON_FK_MOON_O \"\\xef\\x86\\x86\"\t// U+f186\n#define ICON_FK_ARCHIVE \"\\xef\\x86\\x87\"\t// U+f187\n#define ICON_FK_BUG \"\\xef\\x86\\x88\"\t// U+f188\n#define ICON_FK_VK \"\\xef\\x86\\x89\"\t// U+f189\n#define ICON_FK_WEIBO \"\\xef\\x86\\x8a\"\t// U+f18a\n#define ICON_FK_RENREN \"\\xef\\x86\\x8b\"\t// U+f18b\n#define ICON_FK_PAGELINES \"\\xef\\x86\\x8c\"\t// U+f18c\n#define ICON_FK_STACK_EXCHANGE \"\\xef\\x86\\x8d\"\t// U+f18d\n#define ICON_FK_ARROW_CIRCLE_O_RIGHT \"\\xef\\x86\\x8e\"\t// U+f18e\n#define ICON_FK_ARROW_CIRCLE_O_LEFT \"\\xef\\x86\\x90\"\t// U+f190\n#define ICON_FK_CARET_SQUARE_O_LEFT \"\\xef\\x86\\x91\"\t// U+f191\n#define ICON_FK_DOT_CIRCLE_O \"\\xef\\x86\\x92\"\t// U+f192\n#define ICON_FK_WHEELCHAIR \"\\xef\\x86\\x93\"\t// U+f193\n#define ICON_FK_VIMEO_SQUARE \"\\xef\\x86\\x94\"\t// U+f194\n#define ICON_FK_TRY \"\\xef\\x86\\x95\"\t// U+f195\n#define ICON_FK_PLUS_SQUARE_O \"\\xef\\x86\\x96\"\t// U+f196\n#define ICON_FK_SPACE_SHUTTLE \"\\xef\\x86\\x97\"\t// U+f197\n#define ICON_FK_SLACK \"\\xef\\x86\\x98\"\t// U+f198\n#define ICON_FK_ENVELOPE_SQUARE \"\\xef\\x86\\x99\"\t// U+f199\n#define ICON_FK_WORDPRESS \"\\xef\\x86\\x9a\"\t// U+f19a\n#define ICON_FK_OPENID \"\\xef\\x86\\x9b\"\t// U+f19b\n#define ICON_FK_UNIVERSITY \"\\xef\\x86\\x9c\"\t// U+f19c\n#define ICON_FK_GRADUATION_CAP \"\\xef\\x86\\x9d\"\t// U+f19d\n#define ICON_FK_YAHOO \"\\xef\\x86\\x9e\"\t// U+f19e\n#define ICON_FK_GOOGLE \"\\xef\\x86\\xa0\"\t// U+f1a0\n#define ICON_FK_REDDIT \"\\xef\\x86\\xa1\"\t// U+f1a1\n#define ICON_FK_REDDIT_SQUARE \"\\xef\\x86\\xa2\"\t// U+f1a2\n#define ICON_FK_STUMBLEUPON_CIRCLE \"\\xef\\x86\\xa3\"\t// U+f1a3\n#define ICON_FK_STUMBLEUPON \"\\xef\\x86\\xa4\"\t// U+f1a4\n#define ICON_FK_DELICIOUS \"\\xef\\x86\\xa5\"\t// U+f1a5\n#define ICON_FK_DIGG \"\\xef\\x86\\xa6\"\t// U+f1a6\n#define ICON_FK_DRUPAL \"\\xef\\x86\\xa9\"\t// U+f1a9\n#define ICON_FK_JOOMLA \"\\xef\\x86\\xaa\"\t// U+f1aa\n#define ICON_FK_LANGUAGE \"\\xef\\x86\\xab\"\t// U+f1ab\n#define ICON_FK_FAX \"\\xef\\x86\\xac\"\t// U+f1ac\n#define ICON_FK_BUILDING \"\\xef\\x86\\xad\"\t// U+f1ad\n#define ICON_FK_CHILD \"\\xef\\x86\\xae\"\t// U+f1ae\n#define ICON_FK_PAW \"\\xef\\x86\\xb0\"\t// U+f1b0\n#define ICON_FK_SPOON \"\\xef\\x86\\xb1\"\t// U+f1b1\n#define ICON_FK_CUBE \"\\xef\\x86\\xb2\"\t// U+f1b2\n#define ICON_FK_CUBES \"\\xef\\x86\\xb3\"\t// U+f1b3\n#define ICON_FK_BEHANCE \"\\xef\\x86\\xb4\"\t// U+f1b4\n#define ICON_FK_BEHANCE_SQUARE \"\\xef\\x86\\xb5\"\t// U+f1b5\n#define ICON_FK_STEAM \"\\xef\\x86\\xb6\"\t// U+f1b6\n#define ICON_FK_STEAM_SQUARE \"\\xef\\x86\\xb7\"\t// U+f1b7\n#define ICON_FK_RECYCLE \"\\xef\\x86\\xb8\"\t// U+f1b8\n#define ICON_FK_CAR \"\\xef\\x86\\xb9\"\t// U+f1b9\n#define ICON_FK_TAXI \"\\xef\\x86\\xba\"\t// U+f1ba\n#define ICON_FK_TREE \"\\xef\\x86\\xbb\"\t// U+f1bb\n#define ICON_FK_SPOTIFY \"\\xef\\x86\\xbc\"\t// U+f1bc\n#define ICON_FK_DEVIANTART \"\\xef\\x86\\xbd\"\t// U+f1bd\n#define ICON_FK_SOUNDCLOUD \"\\xef\\x86\\xbe\"\t// U+f1be\n#define ICON_FK_DATABASE \"\\xef\\x87\\x80\"\t// U+f1c0\n#define ICON_FK_FILE_PDF_O \"\\xef\\x87\\x81\"\t// U+f1c1\n#define ICON_FK_FILE_WORD_O \"\\xef\\x87\\x82\"\t// U+f1c2\n#define ICON_FK_FILE_EXCEL_O \"\\xef\\x87\\x83\"\t// U+f1c3\n#define ICON_FK_FILE_POWERPOINT_O \"\\xef\\x87\\x84\"\t// U+f1c4\n#define ICON_FK_FILE_IMAGE_O \"\\xef\\x87\\x85\"\t// U+f1c5\n#define ICON_FK_FILE_ARCHIVE_O \"\\xef\\x87\\x86\"\t// U+f1c6\n#define ICON_FK_FILE_AUDIO_O \"\\xef\\x87\\x87\"\t// U+f1c7\n#define ICON_FK_FILE_VIDEO_O \"\\xef\\x87\\x88\"\t// U+f1c8\n#define ICON_FK_FILE_CODE_O \"\\xef\\x87\\x89\"\t// U+f1c9\n#define ICON_FK_VINE \"\\xef\\x87\\x8a\"\t// U+f1ca\n#define ICON_FK_CODEPEN \"\\xef\\x87\\x8b\"\t// U+f1cb\n#define ICON_FK_JSFIDDLE \"\\xef\\x87\\x8c\"\t// U+f1cc\n#define ICON_FK_LIFE_RING \"\\xef\\x87\\x8d\"\t// U+f1cd\n#define ICON_FK_CIRCLE_O_NOTCH \"\\xef\\x87\\x8e\"\t// U+f1ce\n#define ICON_FK_REBEL \"\\xef\\x87\\x90\"\t// U+f1d0\n#define ICON_FK_EMPIRE \"\\xef\\x87\\x91\"\t// U+f1d1\n#define ICON_FK_GIT_SQUARE \"\\xef\\x87\\x92\"\t// U+f1d2\n#define ICON_FK_GIT \"\\xef\\x87\\x93\"\t// U+f1d3\n#define ICON_FK_HACKER_NEWS \"\\xef\\x87\\x94\"\t// U+f1d4\n#define ICON_FK_TENCENT_WEIBO \"\\xef\\x87\\x95\"\t// U+f1d5\n#define ICON_FK_QQ \"\\xef\\x87\\x96\"\t// U+f1d6\n#define ICON_FK_WEIXIN \"\\xef\\x87\\x97\"\t// U+f1d7\n#define ICON_FK_PAPER_PLANE \"\\xef\\x87\\x98\"\t// U+f1d8\n#define ICON_FK_PAPER_PLANE_O \"\\xef\\x87\\x99\"\t// U+f1d9\n#define ICON_FK_HISTORY \"\\xef\\x87\\x9a\"\t// U+f1da\n#define ICON_FK_CIRCLE_THIN \"\\xef\\x87\\x9b\"\t// U+f1db\n#define ICON_FK_HEADER \"\\xef\\x87\\x9c\"\t// U+f1dc\n#define ICON_FK_PARAGRAPH \"\\xef\\x87\\x9d\"\t// U+f1dd\n#define ICON_FK_SLIDERS \"\\xef\\x87\\x9e\"\t// U+f1de\n#define ICON_FK_SHARE_ALT \"\\xef\\x87\\xa0\"\t// U+f1e0\n#define ICON_FK_SHARE_ALT_SQUARE \"\\xef\\x87\\xa1\"\t// U+f1e1\n#define ICON_FK_BOMB \"\\xef\\x87\\xa2\"\t// U+f1e2\n#define ICON_FK_FUTBOL_O \"\\xef\\x87\\xa3\"\t// U+f1e3\n#define ICON_FK_TTY \"\\xef\\x87\\xa4\"\t// U+f1e4\n#define ICON_FK_BINOCULARS \"\\xef\\x87\\xa5\"\t// U+f1e5\n#define ICON_FK_PLUG \"\\xef\\x87\\xa6\"\t// U+f1e6\n#define ICON_FK_SLIDESHARE \"\\xef\\x87\\xa7\"\t// U+f1e7\n#define ICON_FK_TWITCH \"\\xef\\x87\\xa8\"\t// U+f1e8\n#define ICON_FK_YELP \"\\xef\\x87\\xa9\"\t// U+f1e9\n#define ICON_FK_NEWSPAPER_O \"\\xef\\x87\\xaa\"\t// U+f1ea\n#define ICON_FK_WIFI \"\\xef\\x87\\xab\"\t// U+f1eb\n#define ICON_FK_CALCULATOR \"\\xef\\x87\\xac\"\t// U+f1ec\n#define ICON_FK_PAYPAL \"\\xef\\x87\\xad\"\t// U+f1ed\n#define ICON_FK_GOOGLE_WALLET \"\\xef\\x87\\xae\"\t// U+f1ee\n#define ICON_FK_CC_VISA \"\\xef\\x87\\xb0\"\t// U+f1f0\n#define ICON_FK_CC_MASTERCARD \"\\xef\\x87\\xb1\"\t// U+f1f1\n#define ICON_FK_CC_DISCOVER \"\\xef\\x87\\xb2\"\t// U+f1f2\n#define ICON_FK_CC_AMEX \"\\xef\\x87\\xb3\"\t// U+f1f3\n#define ICON_FK_CC_PAYPAL \"\\xef\\x87\\xb4\"\t// U+f1f4\n#define ICON_FK_CC_STRIPE \"\\xef\\x87\\xb5\"\t// U+f1f5\n#define ICON_FK_BELL_SLASH \"\\xef\\x87\\xb6\"\t// U+f1f6\n#define ICON_FK_BELL_SLASH_O \"\\xef\\x87\\xb7\"\t// U+f1f7\n#define ICON_FK_TRASH \"\\xef\\x87\\xb8\"\t// U+f1f8\n#define ICON_FK_COPYRIGHT \"\\xef\\x87\\xb9\"\t// U+f1f9\n#define ICON_FK_AT \"\\xef\\x87\\xba\"\t// U+f1fa\n#define ICON_FK_EYEDROPPER \"\\xef\\x87\\xbb\"\t// U+f1fb\n#define ICON_FK_PAINT_BRUSH \"\\xef\\x87\\xbc\"\t// U+f1fc\n#define ICON_FK_BIRTHDAY_CAKE \"\\xef\\x87\\xbd\"\t// U+f1fd\n#define ICON_FK_AREA_CHART \"\\xef\\x87\\xbe\"\t// U+f1fe\n#define ICON_FK_PIE_CHART \"\\xef\\x88\\x80\"\t// U+f200\n#define ICON_FK_LINE_CHART \"\\xef\\x88\\x81\"\t// U+f201\n#define ICON_FK_LASTFM \"\\xef\\x88\\x82\"\t// U+f202\n#define ICON_FK_LASTFM_SQUARE \"\\xef\\x88\\x83\"\t// U+f203\n#define ICON_FK_TOGGLE_OFF \"\\xef\\x88\\x84\"\t// U+f204\n#define ICON_FK_TOGGLE_ON \"\\xef\\x88\\x85\"\t// U+f205\n#define ICON_FK_BICYCLE \"\\xef\\x88\\x86\"\t// U+f206\n#define ICON_FK_BUS \"\\xef\\x88\\x87\"\t// U+f207\n#define ICON_FK_IOXHOST \"\\xef\\x88\\x88\"\t// U+f208\n#define ICON_FK_ANGELLIST \"\\xef\\x88\\x89\"\t// U+f209\n#define ICON_FK_CC \"\\xef\\x88\\x8a\"\t// U+f20a\n#define ICON_FK_ILS \"\\xef\\x88\\x8b\"\t// U+f20b\n#define ICON_FK_MEANPATH \"\\xef\\x88\\x8c\"\t// U+f20c\n#define ICON_FK_BUYSELLADS \"\\xef\\x88\\x8d\"\t// U+f20d\n#define ICON_FK_CONNECTDEVELOP \"\\xef\\x88\\x8e\"\t// U+f20e\n#define ICON_FK_DASHCUBE \"\\xef\\x88\\x90\"\t// U+f210\n#define ICON_FK_FORUMBEE \"\\xef\\x88\\x91\"\t// U+f211\n#define ICON_FK_LEANPUB \"\\xef\\x88\\x92\"\t// U+f212\n#define ICON_FK_SELLSY \"\\xef\\x88\\x93\"\t// U+f213\n#define ICON_FK_SHIRTSINBULK \"\\xef\\x88\\x94\"\t// U+f214\n#define ICON_FK_SIMPLYBUILT \"\\xef\\x88\\x95\"\t// U+f215\n#define ICON_FK_SKYATLAS \"\\xef\\x88\\x96\"\t// U+f216\n#define ICON_FK_CART_PLUS \"\\xef\\x88\\x97\"\t// U+f217\n#define ICON_FK_CART_ARROW_DOWN \"\\xef\\x88\\x98\"\t// U+f218\n#define ICON_FK_DIAMOND \"\\xef\\x88\\x99\"\t// U+f219\n#define ICON_FK_SHIP \"\\xef\\x88\\x9a\"\t// U+f21a\n#define ICON_FK_USER_SECRET \"\\xef\\x88\\x9b\"\t// U+f21b\n#define ICON_FK_MOTORCYCLE \"\\xef\\x88\\x9c\"\t// U+f21c\n#define ICON_FK_STREET_VIEW \"\\xef\\x88\\x9d\"\t// U+f21d\n#define ICON_FK_HEARTBEAT \"\\xef\\x88\\x9e\"\t// U+f21e\n#define ICON_FK_VENUS \"\\xef\\x88\\xa1\"\t// U+f221\n#define ICON_FK_MARS \"\\xef\\x88\\xa2\"\t// U+f222\n#define ICON_FK_MERCURY \"\\xef\\x88\\xa3\"\t// U+f223\n#define ICON_FK_TRANSGENDER \"\\xef\\x88\\xa4\"\t// U+f224\n#define ICON_FK_TRANSGENDER_ALT \"\\xef\\x88\\xa5\"\t// U+f225\n#define ICON_FK_VENUS_DOUBLE \"\\xef\\x88\\xa6\"\t// U+f226\n#define ICON_FK_MARS_DOUBLE \"\\xef\\x88\\xa7\"\t// U+f227\n#define ICON_FK_VENUS_MARS \"\\xef\\x88\\xa8\"\t// U+f228\n#define ICON_FK_MARS_STROKE \"\\xef\\x88\\xa9\"\t// U+f229\n#define ICON_FK_MARS_STROKE_V \"\\xef\\x88\\xaa\"\t// U+f22a\n#define ICON_FK_MARS_STROKE_H \"\\xef\\x88\\xab\"\t// U+f22b\n#define ICON_FK_NEUTER \"\\xef\\x88\\xac\"\t// U+f22c\n#define ICON_FK_GENDERLESS \"\\xef\\x88\\xad\"\t// U+f22d\n#define ICON_FK_FACEBOOK_OFFICIAL \"\\xef\\x88\\xb0\"\t// U+f230\n#define ICON_FK_PINTEREST_P \"\\xef\\x88\\xb1\"\t// U+f231\n#define ICON_FK_WHATSAPP \"\\xef\\x88\\xb2\"\t// U+f232\n#define ICON_FK_SERVER \"\\xef\\x88\\xb3\"\t// U+f233\n#define ICON_FK_USER_PLUS \"\\xef\\x88\\xb4\"\t// U+f234\n#define ICON_FK_USER_TIMES \"\\xef\\x88\\xb5\"\t// U+f235\n#define ICON_FK_BED \"\\xef\\x88\\xb6\"\t// U+f236\n#define ICON_FK_VIACOIN \"\\xef\\x88\\xb7\"\t// U+f237\n#define ICON_FK_TRAIN \"\\xef\\x88\\xb8\"\t// U+f238\n#define ICON_FK_SUBWAY \"\\xef\\x88\\xb9\"\t// U+f239\n#define ICON_FK_MEDIUM \"\\xef\\x88\\xba\"\t// U+f23a\n#define ICON_FK_MEDIUM_SQUARE \"\\xef\\x8b\\xb8\"\t// U+f2f8\n#define ICON_FK_Y_COMBINATOR \"\\xef\\x88\\xbb\"\t// U+f23b\n#define ICON_FK_OPTIN_MONSTER \"\\xef\\x88\\xbc\"\t// U+f23c\n#define ICON_FK_OPENCART \"\\xef\\x88\\xbd\"\t// U+f23d\n#define ICON_FK_EXPEDITEDSSL \"\\xef\\x88\\xbe\"\t// U+f23e\n#define ICON_FK_BATTERY_FULL \"\\xef\\x89\\x80\"\t// U+f240\n#define ICON_FK_BATTERY_THREE_QUARTERS \"\\xef\\x89\\x81\"\t// U+f241\n#define ICON_FK_BATTERY_HALF \"\\xef\\x89\\x82\"\t// U+f242\n#define ICON_FK_BATTERY_QUARTER \"\\xef\\x89\\x83\"\t// U+f243\n#define ICON_FK_BATTERY_EMPTY \"\\xef\\x89\\x84\"\t// U+f244\n#define ICON_FK_MOUSE_POINTER \"\\xef\\x89\\x85\"\t// U+f245\n#define ICON_FK_I_CURSOR \"\\xef\\x89\\x86\"\t// U+f246\n#define ICON_FK_OBJECT_GROUP \"\\xef\\x89\\x87\"\t// U+f247\n#define ICON_FK_OBJECT_UNGROUP \"\\xef\\x89\\x88\"\t// U+f248\n#define ICON_FK_STICKY_NOTE \"\\xef\\x89\\x89\"\t// U+f249\n#define ICON_FK_STICKY_NOTE_O \"\\xef\\x89\\x8a\"\t// U+f24a\n#define ICON_FK_CC_JCB \"\\xef\\x89\\x8b\"\t// U+f24b\n#define ICON_FK_CC_DINERS_CLUB \"\\xef\\x89\\x8c\"\t// U+f24c\n#define ICON_FK_CLONE \"\\xef\\x89\\x8d\"\t// U+f24d\n#define ICON_FK_BALANCE_SCALE \"\\xef\\x89\\x8e\"\t// U+f24e\n#define ICON_FK_HOURGLASS_O \"\\xef\\x89\\x90\"\t// U+f250\n#define ICON_FK_HOURGLASS_START \"\\xef\\x89\\x91\"\t// U+f251\n#define ICON_FK_HOURGLASS_HALF \"\\xef\\x89\\x92\"\t// U+f252\n#define ICON_FK_HOURGLASS_END \"\\xef\\x89\\x93\"\t// U+f253\n#define ICON_FK_HOURGLASS \"\\xef\\x89\\x94\"\t// U+f254\n#define ICON_FK_HAND_ROCK_O \"\\xef\\x89\\x95\"\t// U+f255\n#define ICON_FK_HAND_PAPER_O \"\\xef\\x89\\x96\"\t// U+f256\n#define ICON_FK_HAND_SCISSORS_O \"\\xef\\x89\\x97\"\t// U+f257\n#define ICON_FK_HAND_LIZARD_O \"\\xef\\x89\\x98\"\t// U+f258\n#define ICON_FK_HAND_SPOCK_O \"\\xef\\x89\\x99\"\t// U+f259\n#define ICON_FK_HAND_POINTER_O \"\\xef\\x89\\x9a\"\t// U+f25a\n#define ICON_FK_HAND_PEACE_O \"\\xef\\x89\\x9b\"\t// U+f25b\n#define ICON_FK_TRADEMARK \"\\xef\\x89\\x9c\"\t// U+f25c\n#define ICON_FK_REGISTERED \"\\xef\\x89\\x9d\"\t// U+f25d\n#define ICON_FK_CREATIVE_COMMONS \"\\xef\\x89\\x9e\"\t// U+f25e\n#define ICON_FK_GG \"\\xef\\x89\\xa0\"\t// U+f260\n#define ICON_FK_GG_CIRCLE \"\\xef\\x89\\xa1\"\t// U+f261\n#define ICON_FK_TRIPADVISOR \"\\xef\\x89\\xa2\"\t// U+f262\n#define ICON_FK_ODNOKLASSNIKI \"\\xef\\x89\\xa3\"\t// U+f263\n#define ICON_FK_ODNOKLASSNIKI_SQUARE \"\\xef\\x89\\xa4\"\t// U+f264\n#define ICON_FK_GET_POCKET \"\\xef\\x89\\xa5\"\t// U+f265\n#define ICON_FK_WIKIPEDIA_W \"\\xef\\x89\\xa6\"\t// U+f266\n#define ICON_FK_SAFARI \"\\xef\\x89\\xa7\"\t// U+f267\n#define ICON_FK_CHROME \"\\xef\\x89\\xa8\"\t// U+f268\n#define ICON_FK_FIREFOX \"\\xef\\x89\\xa9\"\t// U+f269\n#define ICON_FK_OPERA \"\\xef\\x89\\xaa\"\t// U+f26a\n#define ICON_FK_INTERNET_EXPLORER \"\\xef\\x89\\xab\"\t// U+f26b\n#define ICON_FK_TELEVISION \"\\xef\\x89\\xac\"\t// U+f26c\n#define ICON_FK_CONTAO \"\\xef\\x89\\xad\"\t// U+f26d\n#define ICON_FK_500PX \"\\xef\\x89\\xae\"\t// U+f26e\n#define ICON_FK_AMAZON \"\\xef\\x89\\xb0\"\t// U+f270\n#define ICON_FK_CALENDAR_PLUS_O \"\\xef\\x89\\xb1\"\t// U+f271\n#define ICON_FK_CALENDAR_MINUS_O \"\\xef\\x89\\xb2\"\t// U+f272\n#define ICON_FK_CALENDAR_TIMES_O \"\\xef\\x89\\xb3\"\t// U+f273\n#define ICON_FK_CALENDAR_CHECK_O \"\\xef\\x89\\xb4\"\t// U+f274\n#define ICON_FK_INDUSTRY \"\\xef\\x89\\xb5\"\t// U+f275\n#define ICON_FK_MAP_PIN \"\\xef\\x89\\xb6\"\t// U+f276\n#define ICON_FK_MAP_SIGNS \"\\xef\\x89\\xb7\"\t// U+f277\n#define ICON_FK_MAP_O \"\\xef\\x89\\xb8\"\t// U+f278\n#define ICON_FK_MAP \"\\xef\\x89\\xb9\"\t// U+f279\n#define ICON_FK_COMMENTING \"\\xef\\x89\\xba\"\t// U+f27a\n#define ICON_FK_COMMENTING_O \"\\xef\\x89\\xbb\"\t// U+f27b\n#define ICON_FK_HOUZZ \"\\xef\\x89\\xbc\"\t// U+f27c\n#define ICON_FK_VIMEO \"\\xef\\x89\\xbd\"\t// U+f27d\n#define ICON_FK_BLACK_TIE \"\\xef\\x89\\xbe\"\t// U+f27e\n#define ICON_FK_FONTICONS \"\\xef\\x8a\\x80\"\t// U+f280\n#define ICON_FK_REDDIT_ALIEN \"\\xef\\x8a\\x81\"\t// U+f281\n#define ICON_FK_EDGE \"\\xef\\x8a\\x82\"\t// U+f282\n#define ICON_FK_CREDIT_CARD_ALT \"\\xef\\x8a\\x83\"\t// U+f283\n#define ICON_FK_CODIEPIE \"\\xef\\x8a\\x84\"\t// U+f284\n#define ICON_FK_MODX \"\\xef\\x8a\\x85\"\t// U+f285\n#define ICON_FK_FORT_AWESOME \"\\xef\\x8a\\x86\"\t// U+f286\n#define ICON_FK_USB \"\\xef\\x8a\\x87\"\t// U+f287\n#define ICON_FK_PRODUCT_HUNT \"\\xef\\x8a\\x88\"\t// U+f288\n#define ICON_FK_MIXCLOUD \"\\xef\\x8a\\x89\"\t// U+f289\n#define ICON_FK_SCRIBD \"\\xef\\x8a\\x8a\"\t// U+f28a\n#define ICON_FK_PAUSE_CIRCLE \"\\xef\\x8a\\x8b\"\t// U+f28b\n#define ICON_FK_PAUSE_CIRCLE_O \"\\xef\\x8a\\x8c\"\t// U+f28c\n#define ICON_FK_STOP_CIRCLE \"\\xef\\x8a\\x8d\"\t// U+f28d\n#define ICON_FK_STOP_CIRCLE_O \"\\xef\\x8a\\x8e\"\t// U+f28e\n#define ICON_FK_SHOPPING_BAG \"\\xef\\x8a\\x90\"\t// U+f290\n#define ICON_FK_SHOPPING_BASKET \"\\xef\\x8a\\x91\"\t// U+f291\n#define ICON_FK_HASHTAG \"\\xef\\x8a\\x92\"\t// U+f292\n#define ICON_FK_BLUETOOTH \"\\xef\\x8a\\x93\"\t// U+f293\n#define ICON_FK_BLUETOOTH_B \"\\xef\\x8a\\x94\"\t// U+f294\n#define ICON_FK_PERCENT \"\\xef\\x8a\\x95\"\t// U+f295\n#define ICON_FK_GITLAB \"\\xef\\x8a\\x96\"\t// U+f296\n#define ICON_FK_WPBEGINNER \"\\xef\\x8a\\x97\"\t// U+f297\n#define ICON_FK_WPFORMS \"\\xef\\x8a\\x98\"\t// U+f298\n#define ICON_FK_ENVIRA \"\\xef\\x8a\\x99\"\t// U+f299\n#define ICON_FK_UNIVERSAL_ACCESS \"\\xef\\x8a\\x9a\"\t// U+f29a\n#define ICON_FK_WHEELCHAIR_ALT \"\\xef\\x8a\\x9b\"\t// U+f29b\n#define ICON_FK_QUESTION_CIRCLE_O \"\\xef\\x8a\\x9c\"\t// U+f29c\n#define ICON_FK_BLIND \"\\xef\\x8a\\x9d\"\t// U+f29d\n#define ICON_FK_AUDIO_DESCRIPTION \"\\xef\\x8a\\x9e\"\t// U+f29e\n#define ICON_FK_VOLUME_CONTROL_PHONE \"\\xef\\x8a\\xa0\"\t// U+f2a0\n#define ICON_FK_BRAILLE \"\\xef\\x8a\\xa1\"\t// U+f2a1\n#define ICON_FK_ASSISTIVE_LISTENING_SYSTEMS \"\\xef\\x8a\\xa2\"\t// U+f2a2\n#define ICON_FK_AMERICAN_SIGN_LANGUAGE_INTERPRETING \"\\xef\\x8a\\xa3\"\t// U+f2a3\n#define ICON_FK_DEAF \"\\xef\\x8a\\xa4\"\t// U+f2a4\n#define ICON_FK_GLIDE \"\\xef\\x8a\\xa5\"\t// U+f2a5\n#define ICON_FK_GLIDE_G \"\\xef\\x8a\\xa6\"\t// U+f2a6\n#define ICON_FK_SIGN_LANGUAGE \"\\xef\\x8a\\xa7\"\t// U+f2a7\n#define ICON_FK_LOW_VISION \"\\xef\\x8a\\xa8\"\t// U+f2a8\n#define ICON_FK_VIADEO \"\\xef\\x8a\\xa9\"\t// U+f2a9\n#define ICON_FK_VIADEO_SQUARE \"\\xef\\x8a\\xaa\"\t// U+f2aa\n#define ICON_FK_SNAPCHAT \"\\xef\\x8a\\xab\"\t// U+f2ab\n#define ICON_FK_SNAPCHAT_GHOST \"\\xef\\x8a\\xac\"\t// U+f2ac\n#define ICON_FK_SNAPCHAT_SQUARE \"\\xef\\x8a\\xad\"\t// U+f2ad\n#define ICON_FK_FIRST_ORDER \"\\xef\\x8a\\xb0\"\t// U+f2b0\n#define ICON_FK_YOAST \"\\xef\\x8a\\xb1\"\t// U+f2b1\n#define ICON_FK_THEMEISLE \"\\xef\\x8a\\xb2\"\t// U+f2b2\n#define ICON_FK_GOOGLE_PLUS_OFFICIAL \"\\xef\\x8a\\xb3\"\t// U+f2b3\n#define ICON_FK_FONT_AWESOME \"\\xef\\x8a\\xb4\"\t// U+f2b4\n#define ICON_FK_HANDSHAKE_O \"\\xef\\x8a\\xb5\"\t// U+f2b5\n#define ICON_FK_ENVELOPE_OPEN \"\\xef\\x8a\\xb6\"\t// U+f2b6\n#define ICON_FK_ENVELOPE_OPEN_O \"\\xef\\x8a\\xb7\"\t// U+f2b7\n#define ICON_FK_LINODE \"\\xef\\x8a\\xb8\"\t// U+f2b8\n#define ICON_FK_ADDRESS_BOOK \"\\xef\\x8a\\xb9\"\t// U+f2b9\n#define ICON_FK_ADDRESS_BOOK_O \"\\xef\\x8a\\xba\"\t// U+f2ba\n#define ICON_FK_ADDRESS_CARD \"\\xef\\x8a\\xbb\"\t// U+f2bb\n#define ICON_FK_ADDRESS_CARD_O \"\\xef\\x8a\\xbc\"\t// U+f2bc\n#define ICON_FK_USER_CIRCLE \"\\xef\\x8a\\xbd\"\t// U+f2bd\n#define ICON_FK_USER_CIRCLE_O \"\\xef\\x8a\\xbe\"\t// U+f2be\n#define ICON_FK_USER_O \"\\xef\\x8b\\x80\"\t// U+f2c0\n#define ICON_FK_ID_BADGE \"\\xef\\x8b\\x81\"\t// U+f2c1\n#define ICON_FK_ID_CARD \"\\xef\\x8b\\x82\"\t// U+f2c2\n#define ICON_FK_ID_CARD_O \"\\xef\\x8b\\x83\"\t// U+f2c3\n#define ICON_FK_QUORA \"\\xef\\x8b\\x84\"\t// U+f2c4\n#define ICON_FK_FREE_CODE_CAMP \"\\xef\\x8b\\x85\"\t// U+f2c5\n#define ICON_FK_TELEGRAM \"\\xef\\x8b\\x86\"\t// U+f2c6\n#define ICON_FK_THERMOMETER_FULL \"\\xef\\x8b\\x87\"\t// U+f2c7\n#define ICON_FK_THERMOMETER_THREE_QUARTERS \"\\xef\\x8b\\x88\"\t// U+f2c8\n#define ICON_FK_THERMOMETER_HALF \"\\xef\\x8b\\x89\"\t// U+f2c9\n#define ICON_FK_THERMOMETER_QUARTER \"\\xef\\x8b\\x8a\"\t// U+f2ca\n#define ICON_FK_THERMOMETER_EMPTY \"\\xef\\x8b\\x8b\"\t// U+f2cb\n#define ICON_FK_SHOWER \"\\xef\\x8b\\x8c\"\t// U+f2cc\n#define ICON_FK_BATH \"\\xef\\x8b\\x8d\"\t// U+f2cd\n#define ICON_FK_PODCAST \"\\xef\\x8b\\x8e\"\t// U+f2ce\n#define ICON_FK_WINDOW_MAXIMIZE \"\\xef\\x8b\\x90\"\t// U+f2d0\n#define ICON_FK_WINDOW_MINIMIZE \"\\xef\\x8b\\x91\"\t// U+f2d1\n#define ICON_FK_WINDOW_RESTORE \"\\xef\\x8b\\x92\"\t// U+f2d2\n#define ICON_FK_WINDOW_CLOSE \"\\xef\\x8b\\x93\"\t// U+f2d3\n#define ICON_FK_WINDOW_CLOSE_O \"\\xef\\x8b\\x94\"\t// U+f2d4\n#define ICON_FK_BANDCAMP \"\\xef\\x8b\\x95\"\t// U+f2d5\n#define ICON_FK_GRAV \"\\xef\\x8b\\x96\"\t// U+f2d6\n#define ICON_FK_ETSY \"\\xef\\x8b\\x97\"\t// U+f2d7\n#define ICON_FK_IMDB \"\\xef\\x8b\\x98\"\t// U+f2d8\n#define ICON_FK_RAVELRY \"\\xef\\x8b\\x99\"\t// U+f2d9\n#define ICON_FK_EERCAST \"\\xef\\x8b\\x9a\"\t// U+f2da\n#define ICON_FK_MICROCHIP \"\\xef\\x8b\\x9b\"\t// U+f2db\n#define ICON_FK_SNOWFLAKE_O \"\\xef\\x8b\\x9c\"\t// U+f2dc\n#define ICON_FK_SUPERPOWERS \"\\xef\\x8b\\x9d\"\t// U+f2dd\n#define ICON_FK_WPEXPLORER \"\\xef\\x8b\\x9e\"\t// U+f2de\n#define ICON_FK_MEETUP \"\\xef\\x8b\\xa0\"\t// U+f2e0\n#define ICON_FK_MASTODON \"\\xef\\x8b\\xa1\"\t// U+f2e1\n#define ICON_FK_MASTODON_ALT \"\\xef\\x8b\\xa2\"\t// U+f2e2\n#define ICON_FK_FORK_AWESOME \"\\xef\\x8b\\xa3\"\t// U+f2e3\n#define ICON_FK_PEERTUBE \"\\xef\\x8b\\xa4\"\t// U+f2e4\n#define ICON_FK_DIASPORA \"\\xef\\x8b\\xa5\"\t// U+f2e5\n#define ICON_FK_FRIENDICA \"\\xef\\x8b\\xa6\"\t// U+f2e6\n#define ICON_FK_GNU_SOCIAL \"\\xef\\x8b\\xa7\"\t// U+f2e7\n#define ICON_FK_LIBERAPAY_SQUARE \"\\xef\\x8b\\xa8\"\t// U+f2e8\n#define ICON_FK_LIBERAPAY \"\\xef\\x8b\\xa9\"\t// U+f2e9\n#define ICON_FK_SCUTTLEBUTT \"\\xef\\x8b\\xaa\"\t// U+f2ea\n#define ICON_FK_HUBZILLA \"\\xef\\x8b\\xab\"\t// U+f2eb\n#define ICON_FK_SOCIAL_HOME \"\\xef\\x8b\\xac\"\t// U+f2ec\n#define ICON_FK_ARTSTATION \"\\xef\\x8b\\xad\"\t// U+f2ed\n#define ICON_FK_DISCORD \"\\xef\\x8b\\xae\"\t// U+f2ee\n#define ICON_FK_DISCORD_ALT \"\\xef\\x8b\\xaf\"\t// U+f2ef\n#define ICON_FK_PATREON \"\\xef\\x8b\\xb0\"\t// U+f2f0\n#define ICON_FK_SNOWDRIFT \"\\xef\\x8b\\xb1\"\t// U+f2f1\n#define ICON_FK_ACTIVITYPUB \"\\xef\\x8b\\xb2\"\t// U+f2f2\n#define ICON_FK_ETHEREUM \"\\xef\\x8b\\xb3\"\t// U+f2f3\n#define ICON_FK_KEYBASE \"\\xef\\x8b\\xb4\"\t// U+f2f4\n#define ICON_FK_SHAARLI \"\\xef\\x8b\\xb5\"\t// U+f2f5\n#define ICON_FK_SHAARLI_O \"\\xef\\x8b\\xb6\"\t// U+f2f6\n#define ICON_FK_KEY_MODERN \"\\xef\\x8b\\xb7\"\t// U+f2f7\n#define ICON_FK_XMPP \"\\xef\\x8b\\xb9\"\t// U+f2f9\n#define ICON_FK_ARCHIVE_ORG \"\\xef\\x8b\\xbc\"\t// U+f2fc\n#define ICON_FK_FREEDOMBOX \"\\xef\\x8b\\xbd\"\t// U+f2fd\n#define ICON_FK_FACEBOOK_MESSENGER \"\\xef\\x8b\\xbe\"\t// U+f2fe\n#define ICON_FK_DEBIAN \"\\xef\\x8b\\xbf\"\t// U+f2ff\n#define ICON_FK_MASTODON_SQUARE \"\\xef\\x8c\\x80\"\t// U+f300\n#define ICON_FK_TIPEEE \"\\xef\\x8c\\x81\"\t// U+f301\n#define ICON_FK_REACT \"\\xef\\x8c\\x82\"\t// U+f302\n#define ICON_FK_DOGMAZIC \"\\xef\\x8c\\x83\"\t// U+f303\n#define ICON_FK_ZOTERO \"\\xef\\x8c\\x89\"\t// U+f309\n#define ICON_FK_NODEJS \"\\xef\\x8c\\x88\"\t// U+f308\n#define ICON_FK_NEXTCLOUD \"\\xef\\x8c\\x86\"\t// U+f306\n#define ICON_FK_NEXTCLOUD_SQUARE \"\\xef\\x8c\\x87\"\t// U+f307\n#define ICON_FK_HACKADAY \"\\xef\\x8c\\x8a\"\t// U+f30a\n#define ICON_FK_LARAVEL \"\\xef\\x8c\\x8b\"\t// U+f30b\n#define ICON_FK_SIGNALAPP \"\\xef\\x8c\\x8c\"\t// U+f30c\n#define ICON_FK_GNUPG \"\\xef\\x8c\\x8d\"\t// U+f30d\n#define ICON_FK_PHP \"\\xef\\x8c\\x8e\"\t// U+f30e\n#define ICON_FK_FFMPEG \"\\xef\\x8c\\x8f\"\t// U+f30f\n#define ICON_FK_JOPLIN \"\\xef\\x8c\\x90\"\t// U+f310\n#define ICON_FK_SYNCTHING \"\\xef\\x8c\\x91\"\t// U+f311\n#define ICON_FK_INKSCAPE \"\\xef\\x8c\\x92\"\t// U+f312\n#define ICON_FK_MATRIX_ORG \"\\xef\\x8c\\x93\"\t// U+f313\n#define ICON_FK_PIXELFED \"\\xef\\x8c\\x94\"\t// U+f314\n#define ICON_FK_BOOTSTRAP \"\\xef\\x8c\\x95\"\t// U+f315\n#define ICON_FK_DEV_TO \"\\xef\\x8c\\x96\"\t// U+f316\n#define ICON_FK_HASHNODE \"\\xef\\x8c\\x97\"\t// U+f317\n#define ICON_FK_JIRAFEAU \"\\xef\\x8c\\x98\"\t// U+f318\n#define ICON_FK_EMBY \"\\xef\\x8c\\x99\"\t// U+f319\n#define ICON_FK_WIKIDATA \"\\xef\\x8c\\x9a\"\t// U+f31a\n#define ICON_FK_GIMP \"\\xef\\x8c\\x9b\"\t// U+f31b\n#define ICON_FK_C \"\\xef\\x8c\\x9c\"\t// U+f31c\n#define ICON_FK_DIGITALOCEAN \"\\xef\\x8c\\x9d\"\t// U+f31d\n#define ICON_FK_ATT \"\\xef\\x8c\\x9e\"\t// U+f31e\n#define ICON_FK_GITEA \"\\xef\\x8c\\x9f\"\t// U+f31f\n#define ICON_FK_FILE_EPUB \"\\xef\\x8c\\xa1\"\t// U+f321\n#define ICON_FK_PYTHON \"\\xef\\x8c\\xa2\"\t// U+f322\n#define ICON_FK_ARCHLINUX \"\\xef\\x8c\\xa3\"\t// U+f323\n#define ICON_FK_PLEROMA \"\\xef\\x8c\\xa4\"\t// U+f324\n#define ICON_FK_UNSPLASH \"\\xef\\x8c\\xa5\"\t// U+f325\n#define ICON_FK_HACKSTER \"\\xef\\x8c\\xa6\"\t// U+f326\n#define ICON_FK_SPELL_CHECK \"\\xef\\x8c\\xa7\"\t// U+f327\n#define ICON_FK_MOON \"\\xef\\x8c\\xa8\"\t// U+f328\n#define ICON_FK_SUN \"\\xef\\x8c\\xa9\"\t// U+f329\n#define ICON_FK_F_DROID \"\\xef\\x8c\\xaa\"\t// U+f32a\n#define ICON_FK_BIOMETRIC \"\\xef\\x8c\\xab\"\t// U+f32b\n#define ICON_FK_WIRE \"\\xef\\x8c\\xac\"\t// U+f32c\n#define ICON_FK_TOR_ONION \"\\xef\\x8c\\xae\"\t// U+f32e\n#define ICON_FK_VOLUME_MUTE \"\\xef\\x8c\\xaf\"\t// U+f32f\n#define ICON_FK_BELL_RINGING \"\\xef\\x8c\\xad\"\t// U+f32d\n#define ICON_FK_BELL_RINGING_O \"\\xef\\x8c\\xb0\"\t// U+f330\n#define ICON_FK_HAL \"\\xef\\x8c\\xb3\"\t// U+f333\n#define ICON_FK_JUPYTER \"\\xef\\x8c\\xb5\"\t// U+f335\n#define ICON_FK_JULIA \"\\xef\\x8c\\xb4\"\t// U+f334\n#define ICON_FK_CLASSICPRESS \"\\xef\\x8c\\xb1\"\t// U+f331\n#define ICON_FK_CLASSICPRESS_CIRCLE \"\\xef\\x8c\\xb2\"\t// U+f332\n#define ICON_FK_OPEN_COLLECTIVE \"\\xef\\x8c\\xb6\"\t// U+f336\n#define ICON_FK_ORCID \"\\xef\\x8c\\xb7\"\t// U+f337\n#define ICON_FK_RESEARCHGATE \"\\xef\\x8c\\xb8\"\t// U+f338\n#define ICON_FK_FUNKWHALE \"\\xef\\x8c\\xb9\"\t// U+f339\n#define ICON_FK_ASKFM \"\\xef\\x8c\\xba\"\t// U+f33a\n#define ICON_FK_BLOCKSTACK \"\\xef\\x8c\\xbb\"\t// U+f33b\n#define ICON_FK_BOARDGAMEGEEK \"\\xef\\x8c\\xbc\"\t// U+f33c\n#define ICON_FK_BUNNY \"\\xef\\x8d\\x9f\"\t// U+f35f\n#define ICON_FK_BUYMEACOFFEE \"\\xef\\x8c\\xbd\"\t// U+f33d\n#define ICON_FK_CC_BY \"\\xef\\x8c\\xbe\"\t// U+f33e\n#define ICON_FK_CC_CC \"\\xef\\x8c\\xbf\"\t// U+f33f\n#define ICON_FK_CC_NC_EU \"\\xef\\x8d\\x81\"\t// U+f341\n#define ICON_FK_CC_NC_JP \"\\xef\\x8d\\x82\"\t// U+f342\n#define ICON_FK_CC_NC \"\\xef\\x8d\\x80\"\t// U+f340\n#define ICON_FK_CC_ND \"\\xef\\x8d\\x83\"\t// U+f343\n#define ICON_FK_CC_PD \"\\xef\\x8d\\x84\"\t// U+f344\n#define ICON_FK_CC_REMIX \"\\xef\\x8d\\x85\"\t// U+f345\n#define ICON_FK_CC_SA \"\\xef\\x8d\\x86\"\t// U+f346\n#define ICON_FK_CC_SHARE \"\\xef\\x8d\\x87\"\t// U+f347\n#define ICON_FK_CC_ZERO \"\\xef\\x8d\\x88\"\t// U+f348\n#define ICON_FK_CONWAY_GLIDER \"\\xef\\x8d\\x89\"\t// U+f349\n#define ICON_FK_CSHARP \"\\xef\\x8d\\x8a\"\t// U+f34a\n#define ICON_FK_EMAIL_BULK \"\\xef\\x8d\\x8b\"\t// U+f34b\n#define ICON_FK_EMAIL_BULK_O \"\\xef\\x8d\\x8c\"\t// U+f34c\n#define ICON_FK_GNU \"\\xef\\x8d\\x8d\"\t// U+f34d\n#define ICON_FK_GOOGLE_PLAY \"\\xef\\x8d\\x8e\"\t// U+f34e\n#define ICON_FK_HEROKU \"\\xef\\x8d\\x8f\"\t// U+f34f\n#define ICON_FK_HOME_ASSISTANT \"\\xef\\x8d\\x90\"\t// U+f350\n#define ICON_FK_JAVA \"\\xef\\x8d\\x91\"\t// U+f351\n#define ICON_FK_MARIADB \"\\xef\\x8d\\x92\"\t// U+f352\n#define ICON_FK_MARKDOWN \"\\xef\\x8d\\x93\"\t// U+f353\n#define ICON_FK_MYSQL \"\\xef\\x8d\\x94\"\t// U+f354\n#define ICON_FK_NORDCAST \"\\xef\\x8d\\x95\"\t// U+f355\n#define ICON_FK_PLUME \"\\xef\\x8d\\x96\"\t// U+f356\n#define ICON_FK_POSTGRESQL \"\\xef\\x8d\\x97\"\t// U+f357\n#define ICON_FK_SASS_ALT \"\\xef\\x8d\\x99\"\t// U+f359\n#define ICON_FK_SASS \"\\xef\\x8d\\x98\"\t// U+f358\n#define ICON_FK_SKATE \"\\xef\\x8d\\x9a\"\t// U+f35a\n#define ICON_FK_SKETCHFAB \"\\xef\\x8d\\x9b\"\t// U+f35b\n#define ICON_FK_TEX \"\\xef\\x8d\\x9c\"\t// U+f35c\n#define ICON_FK_TEXTPATTERN \"\\xef\\x8d\\x9d\"\t// U+f35d\n#define ICON_FK_UNITY \"\\xef\\x8d\\x9e\"\t// U+f35e \n"
  },
  {
    "path": "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(KHRONOS_STATIC)\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": "include/elfhacks.h",
    "content": "/**\n * \\file src/elfhacks.h\n * \\brief elfhacks application interface\n * \\author Pyry Haulos <pyry.haulos@gmail.com>\n * \\date 2007-2008\n */\n\n/* elfhacks.h -- Various ELF run-time hacks\n  version 0.4.1, March 9th, 2008\n\n  Copyright (C) 2007-2008 Pyry Haulos\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  Pyry Haulos <pyry.haulos@gmail.com>\n*/\n#pragma once\n#include <elf.h>\n#include <link.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n//#define __PUBLIC __attribute__ ((visibility (\"default\")))\n#define __PUBLIC\n\n#if UINTPTR_MAX == 0xffffffffffffffff\n# define __elf64\n#else\n# define __elf32\n#endif\n\n#ifdef __elf64\n# define ELFW_R_SYM ELF64_R_SYM\n# define ElfW_Sword Elf64_Sxword\n#else\n# ifdef __elf32\n#  define ELFW_R_SYM ELF32_R_SYM\n#  define ElfW_Sword Elf32_Sword\n# else\n#  error neither __elf32 nor __elf64 is defined\n# endif\n#endif\n\n/**\n *  \\defgroup elfhacks elfhacks\n *  Elfhacks is a collection of functions that aim for retvieving\n *  or modifying progam's dynamic linking information at run-time.\n *  \\{\n */\n\n/**\n * \\brief elfhacks program object\n */\ntypedef struct {\n\t/** file name */\n\tconst char *name;\n\t/** base address in memory */\n\tElfW(Addr) addr;\n\t/** program headers */\n\tconst ElfW(Phdr) *phdr;\n\t/** number of program headers */\n\tElfW(Half) phnum;\n\t/** .dynamic */\n\tElfW(Dyn) *dynamic;\n\t/** .symtab */\n\tElfW(Sym) *symtab;\n\t/** .strtab */\n\tconst char *strtab;\n\t/** symbol hash table (DT_HASH) */\n\tElfW(Word) *hash;\n\t/** symbol hash table (DT_GNU_HASH) */\n\tElf32_Word *gnu_hash;\n} eh_obj_t;\n\n/**\n * \\brief elfhacks symbol\n */\ntypedef struct {\n\t/** symbol name */\n\tconst char *name;\n\t/** corresponding ElfW(Sym) */\n\tElfW(Sym) *sym;\n\t/** elfhacks object this symbol is associated to */\n\teh_obj_t *obj;\n} eh_sym_t;\n\n/**\n * \\brief elfhacks relocation\n */\ntypedef struct {\n\t/** symbol this relocation is associated to */\n\teh_sym_t *sym;\n\t/** corresponding ElfW(Rel) (NULL if this is Rela) */\n\tElfW(Rel) *rel;\n\t/** corresponding ElfW(Rela) (NULL if this is Rel) */\n\tElfW(Rela) *rela;\n\t/** elfhacks program object */\n\teh_obj_t *obj;\n} eh_rel_t;\n\n/**\n * \\brief Iterate objects callback\n */\ntypedef int (*eh_iterate_obj_callback_func)(eh_obj_t *obj, void *arg);\n/**\n * \\brief Iterate symbols callback\n */\ntypedef int (*eh_iterate_sym_callback_func)(eh_sym_t *sym, void *arg);\n/**\n * \\brief Iterate relocations callback\n */\ntypedef int (*eh_iterate_rel_callback_func)(eh_rel_t *rel, void *arg);\n\n/**\n * \\brief Initializes eh_obj_t for given soname\n *\n * Matching is done using fnmatch() so wildcards and other standard\n * filename metacharacters and expressions work.\n *\n * If soname is NULL, this function returns the main program object.\n * \\param obj elfhacks object\n * \\param soname object's soname (see /proc/pid/maps) or NULL for main\n * \\return 0 on success otherwise a positive error code\n*/\n__PUBLIC int eh_find_obj(eh_obj_t *obj, const char *soname);\n\n/**\n * \\brief Walk through list of objects\n * \\param callback callback function\n * \\param arg argument passed to callback function\n * \\return 0 on success otherwise an error code\n */\n__PUBLIC int eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg);\n\n/**\n * \\brief Finds symbol in object's .dynsym and retrvieves its value.\n * \\param obj elfhacks program object\n * \\param name symbol to find\n * \\param to returned value\n * \\return 0 on success otherwise a positive error code\n*/\n__PUBLIC int eh_find_sym(eh_obj_t *obj, const char *name, void **to);\n\n/**\n * \\brief Walk through list of symbols in object\n * \\param obj elfhacks program object\n * \\param callback callback function\n * \\param arg argument passed to callback function\n * \\return 0 on success otherwise an error code\n */\n__PUBLIC int eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg);\n\n/**\n * \\brief Iterates through object's .rel.plt and .rela.plt and sets every\n *        occurrence of some symbol to the specified value.\n * \\param obj elfhacks program object\n * \\param sym symbol to replace\n * \\param val new value\n * \\return 0 on success otherwise a positive error code\n*/\n__PUBLIC int eh_set_rel(eh_obj_t *obj, const char *sym, void *val);\n\n/**\n * \\brief Walk through object's .rel.plt and .rela.plt\n * \\param obj elfhacks program object\n * \\param callback callback function\n * \\param arg argument passed to callback function\n */\n__PUBLIC int eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg);\n\n/**\n * \\brief Destroy eh_obj_t object.\n * \\param obj elfhacks program object\n * \\return 0 on success otherwise a positive error code\n*/\n__PUBLIC int eh_destroy_obj(eh_obj_t *obj);\n\n/** \\} */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "include/filesystem.h",
    "content": "//---------------------------------------------------------------------------------------\n//\n// ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20\n//\n//---------------------------------------------------------------------------------------\n//\n// Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, 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,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n//\n//---------------------------------------------------------------------------------------\n//\n// To dynamically select std::filesystem where available on most platforms,\n// you could use:\n//\n// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)\n// #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)\n// #define GHC_USE_STD_FS\n// #include <filesystem>\n// namespace fs = std::filesystem;\n// #endif\n// #endif\n// #ifndef GHC_USE_STD_FS\n// #include <ghc/filesystem.hpp>\n// namespace fs = ghc::filesystem;\n// #endif\n//\n//---------------------------------------------------------------------------------------\n#ifndef GHC_FILESYSTEM_H\n#define GHC_FILESYSTEM_H\n\n// #define BSD manifest constant only in\n// sys/param.h\n#ifndef _WIN32\n#include <sys/param.h>\n#endif\n\n#ifndef GHC_OS_DETECTED\n#if defined(__APPLE__) && defined(__MACH__)\n#define GHC_OS_MACOS\n#elif defined(__linux__)\n#define GHC_OS_LINUX\n#if defined(__ANDROID__)\n#define GHC_OS_ANDROID\n#endif\n#elif defined(_WIN64)\n#define GHC_OS_WINDOWS\n#define GHC_OS_WIN64\n#elif defined(_WIN32)\n#define GHC_OS_WINDOWS\n#define GHC_OS_WIN32\n#elif defined(__CYGWIN__)\n#define GHC_OS_CYGWIN\n#elif defined(__svr4__)\n#define GHC_OS_SYS5R4\n#elif defined(BSD)\n#define GHC_OS_BSD\n#elif defined(__EMSCRIPTEN__)\n#define GHC_OS_WEB\n#include <wasi/api.h>\n#else\n#error \"Operating system currently not supported!\"\n#endif\n#define GHC_OS_DETECTED\n#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#if _MSVC_LANG == 201703L\n#define GHC_FILESYSTEM_RUNNING_CPP17\n#else\n#define GHC_FILESYSTEM_RUNNING_CPP20\n#endif\n#elif (defined(__cplusplus) && __cplusplus >= 201703L)\n#if __cplusplus == 201703L\n#define GHC_FILESYSTEM_RUNNING_CPP17\n#else\n#define GHC_FILESYSTEM_RUNNING_CPP20\n#endif\n#endif\n#endif\n\n#if defined(GHC_FILESYSTEM_IMPLEMENTATION)\n#define GHC_EXPAND_IMPL\n#define GHC_INLINE\n#ifdef GHC_OS_WINDOWS\n#ifndef GHC_FS_API\n#define GHC_FS_API\n#endif\n#ifndef GHC_FS_API_CLASS\n#define GHC_FS_API_CLASS\n#endif\n#else\n#ifndef GHC_FS_API\n#define GHC_FS_API __attribute__((visibility(\"default\")))\n#endif\n#ifndef GHC_FS_API_CLASS\n#define GHC_FS_API_CLASS __attribute__((visibility(\"default\")))\n#endif\n#endif\n#elif defined(GHC_FILESYSTEM_FWD)\n#define GHC_INLINE\n#ifdef GHC_OS_WINDOWS\n#ifndef GHC_FS_API\n#define GHC_FS_API extern\n#endif\n#ifndef GHC_FS_API_CLASS\n#define GHC_FS_API_CLASS\n#endif\n#else\n#ifndef GHC_FS_API\n#define GHC_FS_API extern\n#endif\n#ifndef GHC_FS_API_CLASS\n#define GHC_FS_API_CLASS\n#endif\n#endif\n#else\n#define GHC_EXPAND_IMPL\n#define GHC_INLINE inline\n#ifndef GHC_FS_API\n#define GHC_FS_API\n#endif\n#ifndef GHC_FS_API_CLASS\n#define GHC_FS_API_CLASS\n#endif\n#endif\n\n#ifdef GHC_EXPAND_IMPL\n\n#ifdef GHC_OS_WINDOWS\n#include <windows.h>\n// additional includes\n#include <shellapi.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <wchar.h>\n#include <winioctl.h>\n#else\n#include <dirent.h>\n#include <fcntl.h>\n#include <limits.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <unistd.h>\n#ifdef GHC_OS_ANDROID\n#include <android/api-level.h>\n#if __ANDROID_API__ < 12\n#include <sys/syscall.h>\n#endif\n#include <sys/vfs.h>\n#define statvfs statfs\n#else\n#include <sys/statvfs.h>\n#endif\n#ifdef GHC_OS_CYGWIN\n#include <strings.h>\n#endif\n#if !defined(__ANDROID__) || __ANDROID_API__ >= 26\n#include <langinfo.h>\n#endif\n#endif\n#ifdef GHC_OS_MACOS\n#include <Availability.h>\n#endif\n\n#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)\n#if __has_include(<compare>)\n#define GHC_HAS_THREEWAY_COMP\n#include <compare>\n#endif\n#endif\n\n#include <algorithm>\n#include <cctype>\n#include <chrono>\n#include <clocale>\n#include <cstdlib>\n#include <cstring>\n#include <fstream>\n#include <functional>\n#include <memory>\n#include <stack>\n#include <stdexcept>\n#include <string>\n#include <system_error>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#else  // GHC_EXPAND_IMPL\n\n#if defined(__cpp_impl_three_way_comparison) && defined(__has_include)\n#if __has_include(<compare>)\n#define GHC_HAS_THREEWAY_COMP\n#include <compare>\n#endif\n#endif\n#include <chrono>\n#include <fstream>\n#include <memory>\n#include <stack>\n#include <stdexcept>\n#include <string>\n#include <system_error>\n#ifdef GHC_OS_WINDOWS\n#include <vector>\n#endif\n#endif  // GHC_EXPAND_IMPL\n\n// After standard library includes.\n// Standard library support for std::string_view.\n#if defined(__cpp_lib_string_view)\n#define GHC_HAS_STD_STRING_VIEW\n#elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402)\n#define GHC_HAS_STD_STRING_VIEW\n#elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703)\n#define GHC_HAS_STD_STRING_VIEW\n#elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)\n#define GHC_HAS_STD_STRING_VIEW\n#endif\n\n// Standard library support for std::experimental::string_view.\n#if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402)\n#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW\n#elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402)\n#define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW\n#endif\n\n#if defined(GHC_HAS_STD_STRING_VIEW)\n#include <string_view>\n#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)\n#include <experimental/string_view>\n#endif\n\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp):\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// Enforce C++17 API where possible when compiling for C++20, handles the following cases:\n// * fs::path::u8string() returns std::string instead of std::u8string\n// #define GHC_FILESYSTEM_ENFORCE_CPP17_API\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories\n// configure LWG conformance ()\n#define LWG_2682_BEHAVIOUR\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular\n// file with that name, it is superseded by P1164R1, so only activate if really needed\n// #define LWG_2935_BEHAVIOUR\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// LWG #2936 enables new element wise (more expensive) path comparison\n// * if this->root_name().native().compare(p.root_name().native()) != 0 return result\n// * if this->has_root_directory() and !p.has_root_directory() return -1\n// * if !this->has_root_directory() and p.has_root_directory() return -1\n// * else result of element wise comparison of path iteration where first comparison is != 0 or 0\n//   if all comparisons are 0 (on Windows this implementation does case insensitive root_name()\n//   comparison)\n#define LWG_2936_BEHAVIOUR\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2)\n#define LWG_2937_BEHAVIOUR\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows\n// version defaults to std::wstring storage backend. Still all std::string will be interpreted\n// as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using\n// std::string as backend and for fs::path::native() and char for fs::path::c_str(). This\n// needs more conversions so it is (an was before v1.5) slower, bot might help keeping source\n// homogeneous in a multi platform project.\n// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found,\n// instead of replacing them with the unicode replacement character (U+FFFD).\n// #define GHC_RAISE_UNICODE_ERRORS\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n// Automatic prefix windows path with \"\\\\?\\\" if they would break the MAX_PATH length.\n// instead of replacing them with the unicode replacement character (U+FFFD).\n#ifndef GHC_WIN_DISABLE_AUTO_PREFIXES\n#define GHC_WIN_AUTO_PREFIX_LONG_PATH\n#endif  // GHC_WIN_DISABLE_AUTO_PREFIXES\n//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n\n// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)\n#define GHC_FILESYSTEM_VERSION 10504L\n\n#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))\n#define GHC_WITH_EXCEPTIONS\n#endif\n#if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS)\n#error \"Can't raise unicode errors with exception support disabled\"\n#endif\n\nnamespace ghc {\nnamespace filesystem {\n\n#if defined(GHC_HAS_CUSTOM_STRING_VIEW)\n#define GHC_WITH_STRING_VIEW\n#elif defined(GHC_HAS_STD_STRING_VIEW)\n#define GHC_WITH_STRING_VIEW\nusing std::basic_string_view;\n#elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW)\n#define GHC_WITH_STRING_VIEW\nusing std::experimental::basic_string_view;\n#endif\n\n// temporary existing exception type for yet unimplemented parts\nclass GHC_FS_API_CLASS not_implemented_exception : public std::logic_error\n{\npublic:\n    not_implemented_exception()\n        : std::logic_error(\"function not implemented yet.\")\n    {\n    }\n};\n\ntemplate <typename char_type>\nclass path_helper_base\n{\npublic:\n    using value_type = char_type;\n#ifdef GHC_OS_WINDOWS\n    static constexpr value_type preferred_separator = '\\\\';\n#else\n    static constexpr value_type preferred_separator = '/';\n#endif\n};\n\n#if __cplusplus < 201703L\ntemplate <typename char_type>\nconstexpr char_type path_helper_base<char_type>::preferred_separator;\n#endif\n\n#ifdef GHC_OS_WINDOWS\nclass path;\nnamespace detail {\nbool has_executable_extension(const path& p);\n}\n#endif\n\n// 30.10.8 class path\nclass GHC_FS_API_CLASS path\n#if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE)\n#define GHC_USE_WCHAR_T\n#define GHC_NATIVEWP(p) p.c_str()\n#define GHC_PLATFORM_LITERAL(str) L##str\n    : private path_helper_base<std::wstring::value_type>\n{\npublic:\n    using path_helper_base<std::wstring::value_type>::value_type;\n#else\n#define GHC_NATIVEWP(p) p.wstring().c_str()\n#define GHC_PLATFORM_LITERAL(str) str\n    : private path_helper_base<std::string::value_type>\n{\npublic:\n    using path_helper_base<std::string::value_type>::value_type;\n#endif\n    using string_type = std::basic_string<value_type>;\n    using path_helper_base<value_type>::preferred_separator;\n\n    // 30.10.10.1 enumeration format\n    /// The path format in which the constructor argument is given.\n    enum format {\n        generic_format,  ///< The generic format, internally used by\n                         ///< ghc::filesystem::path with slashes\n        native_format,   ///< The format native to the current platform this code\n                         ///< is build for\n        auto_format,     ///< Try to auto-detect the format, fallback to native\n    };\n\n    template <class T>\n    struct _is_basic_string : std::false_type\n    {\n    };\n    template <class CharT, class Traits, class Alloc>\n    struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type\n    {\n    };\n    template <class CharT>\n    struct _is_basic_string<std::basic_string<CharT, std::char_traits<CharT>, std::allocator<CharT>>> : std::true_type\n    {\n    };\n#ifdef GHC_WITH_STRING_VIEW\n    template <class CharT, class Traits>\n    struct _is_basic_string<basic_string_view<CharT, Traits>> : std::true_type\n    {\n    };\n    template <class CharT>\n    struct _is_basic_string<basic_string_view<CharT, std::char_traits<CharT>>> : std::true_type\n    {\n    };\n#endif\n\n    template <typename T1, typename T2 = void>\n    using path_type = typename std::enable_if<!std::is_same<path, T1>::value, path>::type;\n    template <typename T>\n    using path_from_string = typename std::enable_if<_is_basic_string<T>::value || std::is_same<char const*, typename std::decay<T>::type>::value || std::is_same<char*, typename std::decay<T>::type>::value ||\n                                                         std::is_same<wchar_t const*, typename std::decay<T>::type>::value || std::is_same<wchar_t*, typename std::decay<T>::type>::value,\n                                                     path>::type;\n    template <typename T>\n    using path_type_EcharT = typename std::enable_if<std::is_same<T, char>::value || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value, path>::type;\n    // 30.10.8.4.1 constructors and destructor\n    path() noexcept;\n    path(const path& p);\n    path(path&& p) noexcept;\n    path(string_type&& source, format fmt = auto_format);\n    template <class Source, typename = path_from_string<Source>>\n    path(const Source& source, format fmt = auto_format);\n    template <class InputIterator>\n    path(InputIterator first, InputIterator last, format fmt = auto_format);\n#ifdef GHC_WITH_EXCEPTIONS\n    template <class Source, typename = path_from_string<Source>>\n    path(const Source& source, const std::locale& loc, format fmt = auto_format);\n    template <class InputIterator>\n    path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format);\n#endif\n    ~path();\n\n    // 30.10.8.4.2 assignments\n    path& operator=(const path& p);\n    path& operator=(path&& p) noexcept;\n    path& operator=(string_type&& source);\n    path& assign(string_type&& source);\n    template <class Source>\n    path& operator=(const Source& source);\n    template <class Source>\n    path& assign(const Source& source);\n    template <class InputIterator>\n    path& assign(InputIterator first, InputIterator last);\n\n    // 30.10.8.4.3 appends\n    path& operator/=(const path& p);\n    template <class Source>\n    path& operator/=(const Source& source);\n    template <class Source>\n    path& append(const Source& source);\n    template <class InputIterator>\n    path& append(InputIterator first, InputIterator last);\n\n    // 30.10.8.4.4 concatenation\n    path& operator+=(const path& x);\n    path& operator+=(const string_type& x);\n#ifdef GHC_WITH_STRING_VIEW\n    path& operator+=(basic_string_view<value_type> x);\n#endif\n    path& operator+=(const value_type* x);\n    path& operator+=(value_type x);\n    template <class Source>\n    path_from_string<Source>& operator+=(const Source& x);\n    template <class EcharT>\n    path_type_EcharT<EcharT>& operator+=(EcharT x);\n    template <class Source>\n    path& concat(const Source& x);\n    template <class InputIterator>\n    path& concat(InputIterator first, InputIterator last);\n\n    // 30.10.8.4.5 modifiers\n    void clear() noexcept;\n    path& make_preferred();\n    path& remove_filename();\n    path& replace_filename(const path& replacement);\n    path& replace_extension(const path& replacement = path());\n    void swap(path& rhs) noexcept;\n\n    // 30.10.8.4.6 native format observers\n    const string_type& native() const noexcept;\n    const value_type* c_str() const noexcept;\n    operator string_type() const;\n    template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>\n    std::basic_string<EcharT, traits, Allocator> string(const Allocator& a = Allocator()) const;\n    std::string string() const;\n    std::wstring wstring() const;\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\n    std::u8string u8string() const;\n#else\n    std::string u8string() const;\n#endif\n    std::u16string u16string() const;\n    std::u32string u32string() const;\n\n    // 30.10.8.4.7 generic format observers\n    template <class EcharT, class traits = std::char_traits<EcharT>, class Allocator = std::allocator<EcharT>>\n    std::basic_string<EcharT, traits, Allocator> generic_string(const Allocator& a = Allocator()) const;\n    std::string generic_string() const;\n    std::wstring generic_wstring() const;\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\n    std::u8string generic_u8string() const;\n#else\n    std::string generic_u8string() const;\n#endif\n    std::u16string generic_u16string() const;\n    std::u32string generic_u32string() const;\n\n    // 30.10.8.4.8 compare\n    int compare(const path& p) const noexcept;\n    int compare(const string_type& s) const;\n#ifdef GHC_WITH_STRING_VIEW\n    int compare(basic_string_view<value_type> s) const;\n#endif\n    int compare(const value_type* s) const;\n\n    // 30.10.8.4.9 decomposition\n    path root_name() const;\n    path root_directory() const;\n    path root_path() const;\n    path relative_path() const;\n    path parent_path() const;\n    path filename() const;\n    path stem() const;\n    path extension() const;\n\n    // 30.10.8.4.10 query\n    bool empty() const noexcept;\n    bool has_root_name() const;\n    bool has_root_directory() const;\n    bool has_root_path() const;\n    bool has_relative_path() const;\n    bool has_parent_path() const;\n    bool has_filename() const;\n    bool has_stem() const;\n    bool has_extension() const;\n    bool is_absolute() const;\n    bool is_relative() const;\n\n    // 30.10.8.4.11 generation\n    path lexically_normal() const;\n    path lexically_relative(const path& base) const;\n    path lexically_proximate(const path& base) const;\n\n    // 30.10.8.5 iterators\n    class iterator;\n    using const_iterator = iterator;\n    iterator begin() const;\n    iterator end() const;\n\nprivate:\n    using impl_value_type = value_type;\n    using impl_string_type = std::basic_string<impl_value_type>;\n    friend class directory_iterator;\n    void append_name(const value_type* name);\n    static constexpr impl_value_type generic_separator = '/';\n    template <typename InputIterator>\n    class input_iterator_range\n    {\n    public:\n        typedef InputIterator iterator;\n        typedef InputIterator const_iterator;\n        typedef typename InputIterator::difference_type difference_type;\n\n        input_iterator_range(const InputIterator& first, const InputIterator& last)\n            : _first(first)\n            , _last(last)\n        {\n        }\n\n        InputIterator begin() const { return _first; }\n        InputIterator end() const { return _last; }\n\n    private:\n        InputIterator _first;\n        InputIterator _last;\n    };\n    friend void swap(path& lhs, path& rhs) noexcept;\n    friend size_t hash_value(const path& p) noexcept;\n    friend path canonical(const path& p, std::error_code& ec);\n    string_type::size_type root_name_length() const noexcept;\n    void postprocess_path_with_format(format fmt);\n    void check_long_path();\n    impl_string_type _path;\n#ifdef GHC_OS_WINDOWS\n    void handle_prefixes();\n    friend bool detail::has_executable_extension(const path& p);\n#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH\n    string_type::size_type _prefixLength{0};\n#else  // GHC_WIN_AUTO_PREFIX_LONG_PATH\n    static const string_type::size_type _prefixLength{0};\n#endif  // GHC_WIN_AUTO_PREFIX_LONG_PATH\n#else\n    static const string_type::size_type _prefixLength{0};\n#endif\n};\n\n// 30.10.8.6 path non-member functions\nGHC_FS_API void swap(path& lhs, path& rhs) noexcept;\nGHC_FS_API size_t hash_value(const path& p) noexcept;\n#ifdef GHC_HAS_THREEWAY_COMP\nGHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept;\n#endif\nGHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept;\nGHC_FS_API path operator/(const path& lhs, const path& rhs);\n\n// 30.10.8.6.1 path inserter and extractor\ntemplate <class charT, class traits>\nstd::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p);\ntemplate <class charT, class traits>\nstd::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p);\n\n// 30.10.8.6.2 path factory functions\ntemplate <class Source, typename = path::path_from_string<Source>>\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\n[[deprecated(\"use ghc::filesystem::path::path() with std::u8string instead\")]]\n#endif\npath u8path(const Source& source);\ntemplate <class InputIterator>\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\n[[deprecated(\"use ghc::filesystem::path::path() with std::u8string instead\")]]\n#endif\npath u8path(InputIterator first, InputIterator last);\n\n// 30.10.9 class filesystem_error\nclass GHC_FS_API_CLASS filesystem_error : public std::system_error\n{\npublic:\n    filesystem_error(const std::string& what_arg, std::error_code ec);\n    filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec);\n    filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec);\n    const path& path1() const noexcept;\n    const path& path2() const noexcept;\n    const char* what() const noexcept override;\n\nprivate:\n    std::string _what_arg;\n    std::error_code _ec;\n    path _p1, _p2;\n};\n\nclass GHC_FS_API_CLASS path::iterator\n{\npublic:\n    using value_type = const path;\n    using difference_type = std::ptrdiff_t;\n    using pointer = const path*;\n    using reference = const path&;\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    iterator();\n    iterator(const path& p, const impl_string_type::const_iterator& pos);\n    iterator& operator++();\n    iterator operator++(int);\n    iterator& operator--();\n    iterator operator--(int);\n    bool operator==(const iterator& other) const;\n    bool operator!=(const iterator& other) const;\n    reference operator*() const;\n    pointer operator->() const;\n\nprivate:\n    friend class path;\n    impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const;\n    impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const;\n    void updateCurrent();\n    impl_string_type::const_iterator _first;\n    impl_string_type::const_iterator _last;\n    impl_string_type::const_iterator _prefix;\n    impl_string_type::const_iterator _root;\n    impl_string_type::const_iterator _iter;\n    path _current;\n};\n\nstruct space_info\n{\n    uintmax_t capacity;\n    uintmax_t free;\n    uintmax_t available;\n};\n\n// 30.10.10, enumerations\nenum class file_type {\n    none,\n    not_found,\n    regular,\n    directory,\n    symlink,\n    block,\n    character,\n    fifo,\n    socket,\n    unknown,\n};\n\nenum class perms : uint16_t {\n    none = 0,\n\n    owner_read = 0400,\n    owner_write = 0200,\n    owner_exec = 0100,\n    owner_all = 0700,\n\n    group_read = 040,\n    group_write = 020,\n    group_exec = 010,\n    group_all = 070,\n\n    others_read = 04,\n    others_write = 02,\n    others_exec = 01,\n    others_all = 07,\n\n    all = 0777,\n    set_uid = 04000,\n    set_gid = 02000,\n    sticky_bit = 01000,\n\n    mask = 07777,\n    unknown = 0xffff\n};\n\nenum class perm_options : uint16_t {\n    replace = 3,\n    add = 1,\n    remove = 2,\n    nofollow = 4,\n};\n\nenum class copy_options : uint16_t {\n    none = 0,\n\n    skip_existing = 1,\n    overwrite_existing = 2,\n    update_existing = 4,\n\n    recursive = 8,\n\n    copy_symlinks = 0x10,\n    skip_symlinks = 0x20,\n\n    directories_only = 0x40,\n    create_symlinks = 0x80,\n#ifndef GHC_OS_WEB\n    create_hard_links = 0x100\n#endif\n};\n\nenum class directory_options : uint16_t {\n    none = 0,\n    follow_directory_symlink = 1,\n    skip_permission_denied = 2,\n};\n\n// 30.10.11 class file_status\nclass GHC_FS_API_CLASS file_status\n{\npublic:\n    // 30.10.11.1 constructors and destructor\n    file_status() noexcept;\n    explicit file_status(file_type ft, perms prms = perms::unknown) noexcept;\n    file_status(const file_status&) noexcept;\n    file_status(file_status&&) noexcept;\n    ~file_status();\n    // assignments:\n    file_status& operator=(const file_status&) noexcept;\n    file_status& operator=(file_status&&) noexcept;\n    // 30.10.11.3 modifiers\n    void type(file_type ft) noexcept;\n    void permissions(perms prms) noexcept;\n    // 30.10.11.2 observers\n    file_type type() const noexcept;\n    perms permissions() const noexcept;\n    friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); }\nprivate:\n    file_type _type;\n    perms _perms;\n};\n\nusing file_time_type = std::chrono::time_point<std::chrono::system_clock>;\n\n// 30.10.12 Class directory_entry\nclass GHC_FS_API_CLASS directory_entry\n{\npublic:\n    // 30.10.12.1 constructors and destructor\n    directory_entry() noexcept = default;\n    directory_entry(const directory_entry&) = default;\n    directory_entry(directory_entry&&) noexcept = default;\n#ifdef GHC_WITH_EXCEPTIONS\n    explicit directory_entry(const path& p);\n#endif\n    directory_entry(const path& p, std::error_code& ec);\n    ~directory_entry();\n\n    // assignments:\n    directory_entry& operator=(const directory_entry&) = default;\n    directory_entry& operator=(directory_entry&&) noexcept = default;\n\n    // 30.10.12.2 modifiers\n#ifdef GHC_WITH_EXCEPTIONS\n    void assign(const path& p);\n    void replace_filename(const path& p);\n    void refresh();\n#endif\n    void assign(const path& p, std::error_code& ec);\n    void replace_filename(const path& p, std::error_code& ec);\n    void refresh(std::error_code& ec) noexcept;\n\n    // 30.10.12.3 observers\n    const filesystem::path& path() const noexcept;\n    operator const filesystem::path&() const noexcept;\n#ifdef GHC_WITH_EXCEPTIONS\n    bool exists() const;\n    bool is_block_file() const;\n    bool is_character_file() const;\n    bool is_directory() const;\n    bool is_fifo() const;\n    bool is_other() const;\n    bool is_regular_file() const;\n    bool is_socket() const;\n    bool is_symlink() const;\n    uintmax_t file_size() const;\n    file_time_type last_write_time() const;\n    file_status status() const;\n    file_status symlink_status() const;\n#endif\n    bool exists(std::error_code& ec) const noexcept;\n    bool is_block_file(std::error_code& ec) const noexcept;\n    bool is_character_file(std::error_code& ec) const noexcept;\n    bool is_directory(std::error_code& ec) const noexcept;\n    bool is_fifo(std::error_code& ec) const noexcept;\n    bool is_other(std::error_code& ec) const noexcept;\n    bool is_regular_file(std::error_code& ec) const noexcept;\n    bool is_socket(std::error_code& ec) const noexcept;\n    bool is_symlink(std::error_code& ec) const noexcept;\n    uintmax_t file_size(std::error_code& ec) const noexcept;\n    file_time_type last_write_time(std::error_code& ec) const noexcept;\n    file_status status(std::error_code& ec) const noexcept;\n    file_status symlink_status(std::error_code& ec) const noexcept;\n\n#ifndef GHC_OS_WEB\n#ifdef GHC_WITH_EXCEPTIONS\n    uintmax_t hard_link_count() const;\n#endif\n    uintmax_t hard_link_count(std::error_code& ec) const noexcept;\n#endif\n\n#ifdef GHC_HAS_THREEWAY_COMP\n    std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept;\n#endif\n    bool operator<(const directory_entry& rhs) const noexcept;\n    bool operator==(const directory_entry& rhs) const noexcept;\n    bool operator!=(const directory_entry& rhs) const noexcept;\n    bool operator<=(const directory_entry& rhs) const noexcept;\n    bool operator>(const directory_entry& rhs) const noexcept;\n    bool operator>=(const directory_entry& rhs) const noexcept;\n\nprivate:\n    friend class directory_iterator;\n#ifdef GHC_WITH_EXCEPTIONS\n    file_type status_file_type() const;\n#endif\n    file_type status_file_type(std::error_code& ec) const noexcept;\n    filesystem::path _path;\n    file_status _status;\n    file_status _symlink_status;\n    uintmax_t _file_size = static_cast<uintmax_t>(-1);\n#ifndef GHC_OS_WINDOWS\n    uintmax_t _hard_link_count = static_cast<uintmax_t>(-1);\n#endif\n    time_t _last_write_time = 0;\n};\n\n// 30.10.13 Class directory_iterator\nclass GHC_FS_API_CLASS directory_iterator\n{\npublic:\n    class GHC_FS_API_CLASS proxy\n    {\n    public:\n        const directory_entry& operator*() const& noexcept { return _dir_entry; }\n        directory_entry operator*() && noexcept { return std::move(_dir_entry); }\n\n    private:\n        explicit proxy(const directory_entry& dir_entry)\n            : _dir_entry(dir_entry)\n        {\n        }\n        friend class directory_iterator;\n        friend class recursive_directory_iterator;\n        directory_entry _dir_entry;\n    };\n    using iterator_category = std::input_iterator_tag;\n    using value_type = directory_entry;\n    using difference_type = std::ptrdiff_t;\n    using pointer = const directory_entry*;\n    using reference = const directory_entry&;\n\n    // 30.10.13.1 member functions\n    directory_iterator() noexcept;\n#ifdef GHC_WITH_EXCEPTIONS\n    explicit directory_iterator(const path& p);\n    directory_iterator(const path& p, directory_options options);\n#endif\n    directory_iterator(const path& p, std::error_code& ec) noexcept;\n    directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;\n    directory_iterator(const directory_iterator& rhs);\n    directory_iterator(directory_iterator&& rhs) noexcept;\n    ~directory_iterator();\n    directory_iterator& operator=(const directory_iterator& rhs);\n    directory_iterator& operator=(directory_iterator&& rhs) noexcept;\n    const directory_entry& operator*() const;\n    const directory_entry* operator->() const;\n#ifdef GHC_WITH_EXCEPTIONS\n    directory_iterator& operator++();\n#endif\n    directory_iterator& increment(std::error_code& ec) noexcept;\n\n    // other members as required by 27.2.3, input iterators\n#ifdef GHC_WITH_EXCEPTIONS\n    proxy operator++(int)\n    {\n        proxy p{**this};\n        ++*this;\n        return p;\n    }\n#endif\n    bool operator==(const directory_iterator& rhs) const;\n    bool operator!=(const directory_iterator& rhs) const;\n\nprivate:\n    friend class recursive_directory_iterator;\n    class impl;\n    std::shared_ptr<impl> _impl;\n};\n\n// 30.10.13.2 directory_iterator non-member functions\nGHC_FS_API directory_iterator begin(directory_iterator iter) noexcept;\nGHC_FS_API directory_iterator end(const directory_iterator&) noexcept;\n\n// 30.10.14 class recursive_directory_iterator\nclass GHC_FS_API_CLASS recursive_directory_iterator\n{\npublic:\n    using iterator_category = std::input_iterator_tag;\n    using value_type = directory_entry;\n    using difference_type = std::ptrdiff_t;\n    using pointer = const directory_entry*;\n    using reference = const directory_entry&;\n\n    // 30.10.14.1 constructors and destructor\n    recursive_directory_iterator() noexcept;\n#ifdef GHC_WITH_EXCEPTIONS\n    explicit recursive_directory_iterator(const path& p);\n    recursive_directory_iterator(const path& p, directory_options options);\n#endif\n    recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept;\n    recursive_directory_iterator(const path& p, std::error_code& ec) noexcept;\n    recursive_directory_iterator(const recursive_directory_iterator& rhs);\n    recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept;\n    ~recursive_directory_iterator();\n\n    // 30.10.14.1 observers\n    directory_options options() const;\n    int depth() const;\n    bool recursion_pending() const;\n\n    const directory_entry& operator*() const;\n    const directory_entry* operator->() const;\n\n    // 30.10.14.1 modifiers recursive_directory_iterator&\n    recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs);\n    recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept;\n#ifdef GHC_WITH_EXCEPTIONS\n    recursive_directory_iterator& operator++();\n#endif\n    recursive_directory_iterator& increment(std::error_code& ec) noexcept;\n\n#ifdef GHC_WITH_EXCEPTIONS\n    void pop();\n#endif\n    void pop(std::error_code& ec);\n    void disable_recursion_pending();\n\n    // other members as required by 27.2.3, input iterators\n#ifdef GHC_WITH_EXCEPTIONS\n    directory_iterator::proxy operator++(int)\n    {\n        directory_iterator::proxy proxy{**this};\n        ++*this;\n        return proxy;\n    }\n#endif\n    bool operator==(const recursive_directory_iterator& rhs) const;\n    bool operator!=(const recursive_directory_iterator& rhs) const;\n\nprivate:\n    struct recursive_directory_iterator_impl\n    {\n        directory_options _options;\n        bool _recursion_pending;\n        std::stack<directory_iterator> _dir_iter_stack;\n        recursive_directory_iterator_impl(directory_options options, bool recursion_pending)\n            : _options(options)\n            , _recursion_pending(recursion_pending)\n        {\n        }\n    };\n    std::shared_ptr<recursive_directory_iterator_impl> _impl;\n};\n\n// 30.10.14.2 directory_iterator non-member functions\nGHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;\nGHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;\n\n// 30.10.15 filesystem operations\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_FS_API path absolute(const path& p);\nGHC_FS_API path canonical(const path& p);\nGHC_FS_API void copy(const path& from, const path& to);\nGHC_FS_API void copy(const path& from, const path& to, copy_options options);\nGHC_FS_API bool copy_file(const path& from, const path& to);\nGHC_FS_API bool copy_file(const path& from, const path& to, copy_options option);\nGHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink);\nGHC_FS_API bool create_directories(const path& p);\nGHC_FS_API bool create_directory(const path& p);\nGHC_FS_API bool create_directory(const path& p, const path& attributes);\nGHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink);\nGHC_FS_API void create_symlink(const path& to, const path& new_symlink);\nGHC_FS_API path current_path();\nGHC_FS_API void current_path(const path& p);\nGHC_FS_API bool exists(const path& p);\nGHC_FS_API bool equivalent(const path& p1, const path& p2);\nGHC_FS_API uintmax_t file_size(const path& p);\nGHC_FS_API bool is_block_file(const path& p);\nGHC_FS_API bool is_character_file(const path& p);\nGHC_FS_API bool is_directory(const path& p);\nGHC_FS_API bool is_empty(const path& p);\nGHC_FS_API bool is_fifo(const path& p);\nGHC_FS_API bool is_other(const path& p);\nGHC_FS_API bool is_regular_file(const path& p);\nGHC_FS_API bool is_socket(const path& p);\nGHC_FS_API bool is_symlink(const path& p);\nGHC_FS_API file_time_type last_write_time(const path& p);\nGHC_FS_API void last_write_time(const path& p, file_time_type new_time);\nGHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace);\nGHC_FS_API path proximate(const path& p, const path& base = current_path());\nGHC_FS_API path read_symlink(const path& p);\nGHC_FS_API path relative(const path& p, const path& base = current_path());\nGHC_FS_API bool remove(const path& p);\nGHC_FS_API uintmax_t remove_all(const path& p);\nGHC_FS_API void rename(const path& from, const path& to);\nGHC_FS_API void resize_file(const path& p, uintmax_t size);\nGHC_FS_API space_info space(const path& p);\nGHC_FS_API file_status status(const path& p);\nGHC_FS_API file_status symlink_status(const path& p);\nGHC_FS_API path temp_directory_path();\nGHC_FS_API path weakly_canonical(const path& p);\n#endif\nGHC_FS_API path absolute(const path& p, std::error_code& ec);\nGHC_FS_API path canonical(const path& p, std::error_code& ec);\nGHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept;\nGHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept;\nGHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept;\nGHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept;\nGHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept;\nGHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept;\nGHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;\nGHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept;\nGHC_FS_API path current_path(std::error_code& ec);\nGHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool exists(file_status s) noexcept;\nGHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept;\nGHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_block_file(file_status s) noexcept;\nGHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_character_file(file_status s) noexcept;\nGHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_directory(file_status s) noexcept;\nGHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_fifo(file_status s) noexcept;\nGHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_other(file_status s) noexcept;\nGHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_regular_file(file_status s) noexcept;\nGHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_socket(file_status s) noexcept;\nGHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool is_symlink(file_status s) noexcept;\nGHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept;\nGHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept;\nGHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept;\nGHC_FS_API path proximate(const path& p, std::error_code& ec);\nGHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec);\nGHC_FS_API path read_symlink(const path& p, std::error_code& ec);\nGHC_FS_API path relative(const path& p, std::error_code& ec);\nGHC_FS_API path relative(const path& p, const path& base, std::error_code& ec);\nGHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept;\nGHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept;\nGHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API bool status_known(file_status s) noexcept;\nGHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept;\nGHC_FS_API path temp_directory_path(std::error_code& ec) noexcept;\nGHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept;\n\n#ifndef GHC_OS_WEB\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_FS_API void create_hard_link(const path& to, const path& new_hard_link);\nGHC_FS_API uintmax_t hard_link_count(const path& p);\n#endif\nGHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept;\nGHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;\n#endif\n\n// Non-C++17 add-on std::fstream wrappers with path\ntemplate <class charT, class traits = std::char_traits<charT>>\nclass basic_filebuf : public std::basic_filebuf<charT, traits>\n{\npublic:\n    basic_filebuf() {}\n    ~basic_filebuf() override {}\n    basic_filebuf(const basic_filebuf&) = delete;\n    const basic_filebuf& operator=(const basic_filebuf&) = delete;\n    basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode)\n    {\n#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)\n        return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0;\n#else\n        return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0;\n#endif\n    }\n};\n\ntemplate <class charT, class traits = std::char_traits<charT>>\nclass basic_ifstream : public std::basic_ifstream<charT, traits>\n{\npublic:\n    basic_ifstream() {}\n#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)\n    explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)\n        : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.wstring().c_str(), mode); }\n#else\n    explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)\n        : std::basic_ifstream<charT, traits>(p.string().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream<charT, traits>::open(p.string().c_str(), mode); }\n#endif\n    basic_ifstream(const basic_ifstream&) = delete;\n    const basic_ifstream& operator=(const basic_ifstream&) = delete;\n    ~basic_ifstream() override {}\n};\n\ntemplate <class charT, class traits = std::char_traits<charT>>\nclass basic_ofstream : public std::basic_ofstream<charT, traits>\n{\npublic:\n    basic_ofstream() {}\n#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)\n    explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)\n        : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.wstring().c_str(), mode); }\n#else\n    explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)\n        : std::basic_ofstream<charT, traits>(p.string().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream<charT, traits>::open(p.string().c_str(), mode); }\n#endif\n    basic_ofstream(const basic_ofstream&) = delete;\n    const basic_ofstream& operator=(const basic_ofstream&) = delete;\n    ~basic_ofstream() override {}\n};\n\ntemplate <class charT, class traits = std::char_traits<charT>>\nclass basic_fstream : public std::basic_fstream<charT, traits>\n{\npublic:\n    basic_fstream() {}\n#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)\n    explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)\n        : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.wstring().c_str(), mode); }\n#else\n    explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)\n        : std::basic_fstream<charT, traits>(p.string().c_str(), mode)\n    {\n    }\n    void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream<charT, traits>::open(p.string().c_str(), mode); }\n#endif\n    basic_fstream(const basic_fstream&) = delete;\n    const basic_fstream& operator=(const basic_fstream&) = delete;\n    ~basic_fstream() override {}\n};\n\ntypedef basic_filebuf<char> filebuf;\ntypedef basic_filebuf<wchar_t> wfilebuf;\ntypedef basic_ifstream<char> ifstream;\ntypedef basic_ifstream<wchar_t> wifstream;\ntypedef basic_ofstream<char> ofstream;\ntypedef basic_ofstream<wchar_t> wofstream;\ntypedef basic_fstream<char> fstream;\ntypedef basic_fstream<wchar_t> wfstream;\n\nclass GHC_FS_API_CLASS u8arguments\n{\npublic:\n    u8arguments(int& argc, char**& argv);\n    ~u8arguments()\n    {\n        _refargc = _argc;\n        _refargv = _argv;\n    }\n\n    bool valid() const { return _isvalid; }\n\nprivate:\n    int _argc;\n    char** _argv;\n    int& _refargc;\n    char**& _refargv;\n    bool _isvalid;\n#ifdef GHC_OS_WINDOWS\n    std::vector<std::string> _args;\n    std::vector<char*> _argp;\n#endif\n};\n\n//-------------------------------------------------------------------------------------------------\n//  Implementation\n//-------------------------------------------------------------------------------------------------\n\nnamespace detail {\nenum utf8_states_t { S_STRT = 0, S_RJCT = 8 };\nGHC_FS_API void appendUTF8(std::string& str, uint32_t unicode);\nGHC_FS_API bool is_surrogate(uint32_t c);\nGHC_FS_API bool is_high_surrogate(uint32_t c);\nGHC_FS_API bool is_low_surrogate(uint32_t c);\nGHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint);\nenum class portable_error {\n    none = 0,\n    exists,\n    not_found,\n    not_supported,\n    not_implemented,\n    invalid_argument,\n    is_a_directory,\n};\nGHC_FS_API std::error_code make_error_code(portable_error err);\n#ifdef GHC_OS_WINDOWS\nGHC_FS_API std::error_code make_system_error(uint32_t err = 0);\n#else\nGHC_FS_API std::error_code make_system_error(int err = 0);\n#endif\n}  // namespace detail\n\nnamespace detail {\n\n#ifdef GHC_EXPAND_IMPL\n\nGHC_INLINE std::error_code make_error_code(portable_error err)\n{\n#ifdef GHC_OS_WINDOWS\n    switch (err) {\n        case portable_error::none:\n            return std::error_code();\n        case portable_error::exists:\n            return std::error_code(ERROR_ALREADY_EXISTS, std::system_category());\n        case portable_error::not_found:\n            return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category());\n        case portable_error::not_supported:\n            return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());\n        case portable_error::not_implemented:\n            return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category());\n        case portable_error::invalid_argument:\n            return std::error_code(ERROR_INVALID_PARAMETER, std::system_category());\n        case portable_error::is_a_directory:\n#ifdef ERROR_DIRECTORY_NOT_SUPPORTED\n            return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category());\n#else\n            return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());\n#endif\n    }\n#else\n    switch (err) {\n        case portable_error::none:\n            return std::error_code();\n        case portable_error::exists:\n            return std::error_code(EEXIST, std::system_category());\n        case portable_error::not_found:\n            return std::error_code(ENOENT, std::system_category());\n        case portable_error::not_supported:\n            return std::error_code(ENOTSUP, std::system_category());\n        case portable_error::not_implemented:\n            return std::error_code(ENOSYS, std::system_category());\n        case portable_error::invalid_argument:\n            return std::error_code(EINVAL, std::system_category());\n        case portable_error::is_a_directory:\n            return std::error_code(EISDIR, std::system_category());\n    }\n#endif\n    return std::error_code();\n}\n\n#ifdef GHC_OS_WINDOWS\nGHC_INLINE std::error_code make_system_error(uint32_t err)\n{\n    return std::error_code(err ? static_cast<int>(err) : static_cast<int>(::GetLastError()), std::system_category());\n}\n#else\nGHC_INLINE std::error_code make_system_error(int err)\n{\n    return std::error_code(err ? err : errno, std::system_category());\n}\n#endif\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <typename Enum>\nusing EnableBitmask = typename std::enable_if<std::is_same<Enum, perms>::value || std::is_same<Enum, perm_options>::value || std::is_same<Enum, copy_options>::value || std::is_same<Enum, directory_options>::value, Enum>::type;\n}  // namespace detail\n\ntemplate <typename Enum>\nconstexpr detail::EnableBitmask<Enum> operator&(Enum X, Enum Y)\n{\n    using underlying = typename std::underlying_type<Enum>::type;\n    return static_cast<Enum>(static_cast<underlying>(X) & static_cast<underlying>(Y));\n}\n\ntemplate <typename Enum>\nconstexpr detail::EnableBitmask<Enum> operator|(Enum X, Enum Y)\n{\n    using underlying = typename std::underlying_type<Enum>::type;\n    return static_cast<Enum>(static_cast<underlying>(X) | static_cast<underlying>(Y));\n}\n\ntemplate <typename Enum>\nconstexpr detail::EnableBitmask<Enum> operator^(Enum X, Enum Y)\n{\n    using underlying = typename std::underlying_type<Enum>::type;\n    return static_cast<Enum>(static_cast<underlying>(X) ^ static_cast<underlying>(Y));\n}\n\ntemplate <typename Enum>\nconstexpr detail::EnableBitmask<Enum> operator~(Enum X)\n{\n    using underlying = typename std::underlying_type<Enum>::type;\n    return static_cast<Enum>(~static_cast<underlying>(X));\n}\n\ntemplate <typename Enum>\ndetail::EnableBitmask<Enum>& operator&=(Enum& X, Enum Y)\n{\n    X = X & Y;\n    return X;\n}\n\ntemplate <typename Enum>\ndetail::EnableBitmask<Enum>& operator|=(Enum& X, Enum Y)\n{\n    X = X | Y;\n    return X;\n}\n\ntemplate <typename Enum>\ndetail::EnableBitmask<Enum>& operator^=(Enum& X, Enum Y)\n{\n    X = X ^ Y;\n    return X;\n}\n\n#ifdef GHC_EXPAND_IMPL\n\nnamespace detail {\n\nGHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi)\n{\n    return (static_cast<uint32_t>(c - lo) < (hi - lo + 1));\n}\n\nGHC_INLINE bool is_surrogate(uint32_t c)\n{\n    return in_range(c, 0xd800, 0xdfff);\n}\n\nGHC_INLINE bool is_high_surrogate(uint32_t c)\n{\n    return (c & 0xfffffc00) == 0xd800;\n}\n\nGHC_INLINE bool is_low_surrogate(uint32_t c)\n{\n    return (c & 0xfffffc00) == 0xdc00;\n}\n\nGHC_INLINE void appendUTF8(std::string& str, uint32_t unicode)\n{\n    if (unicode <= 0x7f) {\n        str.push_back(static_cast<char>(unicode));\n    }\n    else if (unicode >= 0x80 && unicode <= 0x7ff) {\n        str.push_back(static_cast<char>((unicode >> 6) + 192));\n        str.push_back(static_cast<char>((unicode & 0x3f) + 128));\n    }\n    else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) {\n        str.push_back(static_cast<char>((unicode >> 12) + 224));\n        str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));\n        str.push_back(static_cast<char>((unicode & 0x3f) + 128));\n    }\n    else if (unicode >= 0x10000 && unicode <= 0x10ffff) {\n        str.push_back(static_cast<char>((unicode >> 18) + 240));\n        str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128));\n        str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));\n        str.push_back(static_cast<char>((unicode & 0x3f) + 128));\n    }\n    else {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n        throw filesystem_error(\"Illegal code point for unicode character.\", str, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n        appendUTF8(str, 0xfffd);\n#endif\n    }\n}\n\n// Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/)\n// and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding;\n// Generating debugging and shrinking my own DFA from scratch was a day of fun!\nGHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint)\n{\n    static const uint32_t utf8_state_info[] = {\n        // encoded states\n        0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u,\n        0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u,          0u,          0u,          0u,\n    };\n    uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf;\n    codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment);\n    return state == S_RJCT ? static_cast<unsigned>(S_RJCT) : static_cast<unsigned>((utf8_state_info[category + 16] >> (state << 2)) & 0xf);\n}\n\nGHC_INLINE bool validUtf8(const std::string& utf8String)\n{\n    std::string::const_iterator iter = utf8String.begin();\n    unsigned utf8_state = S_STRT;\n    std::uint32_t codepoint = 0;\n    while (iter < utf8String.end()) {\n        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_RJCT) {\n            return false;\n        }\n    }\n    if (utf8_state) {\n        return false;\n    }\n    return true;\n}\n\n}  // namespace detail\n\n#endif\n\nnamespace detail {\n\ntemplate <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr>\ninline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    return StringType(utf8String.begin(), utf8String.end(), alloc);\n}\n\ntemplate <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr>\ninline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    StringType result(alloc);\n    result.reserve(utf8String.length());\n    auto iter = utf8String.cbegin();\n    unsigned utf8_state = S_STRT;\n    std::uint32_t codepoint = 0;\n    while (iter < utf8String.cend()) {\n        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {\n            if (codepoint <= 0xffff) {\n                result += static_cast<typename StringType::value_type>(codepoint);\n            }\n            else {\n                codepoint -= 0x10000;\n                result += static_cast<typename StringType::value_type>((codepoint >> 10) + 0xd800);\n                result += static_cast<typename StringType::value_type>((codepoint & 0x3ff) + 0xdc00);\n            }\n            codepoint = 0;\n        }\n        else if (utf8_state == S_RJCT) {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n            throw filesystem_error(\"Illegal byte sequence for unicode character.\", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n            result += static_cast<typename StringType::value_type>(0xfffd);\n            utf8_state = S_STRT;\n            codepoint = 0;\n#endif\n        }\n    }\n    if (utf8_state) {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n        throw filesystem_error(\"Illegal byte sequence for unicode character.\", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n        result += static_cast<typename StringType::value_type>(0xfffd);\n#endif\n    }\n    return result;\n}\n\ntemplate <class StringType, class Utf8String, typename std::enable_if<path::_is_basic_string<Utf8String>::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr>\ninline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    StringType result(alloc);\n    result.reserve(utf8String.length());\n    auto iter = utf8String.cbegin();\n    unsigned utf8_state = S_STRT;\n    std::uint32_t codepoint = 0;\n    while (iter < utf8String.cend()) {\n        if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast<uint8_t>(*iter++), codepoint)) == S_STRT) {\n            result += static_cast<typename StringType::value_type>(codepoint);\n            codepoint = 0;\n        }\n        else if (utf8_state == S_RJCT) {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n            throw filesystem_error(\"Illegal byte sequence for unicode character.\", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n            result += static_cast<typename StringType::value_type>(0xfffd);\n            utf8_state = S_STRT;\n            codepoint = 0;\n#endif\n        }\n    }\n    if (utf8_state) {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n        throw filesystem_error(\"Illegal byte sequence for unicode character.\", utf8String, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n        result += static_cast<typename StringType::value_type>(0xfffd);\n#endif\n    }\n    return result;\n}\n\ntemplate <class StringType, typename charT, std::size_t N>\ninline StringType fromUtf8(const charT (&utf8String)[N])\n{\n#ifdef GHC_WITH_STRING_VIEW\n    return fromUtf8<StringType>(basic_string_view<charT>(utf8String, N - 1));\n#else\n    return fromUtf8<StringType>(std::basic_string<charT>(utf8String, N - 1));\n#endif\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1>\ninline std::string toUtf8(const strT& unicodeString)\n{\n    return std::string(unicodeString.begin(), unicodeString.end());\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2>\ninline std::string toUtf8(const strT& unicodeString)\n{\n    std::string result;\n    for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) {\n        char32_t c = *iter;\n        if (is_surrogate(c)) {\n            ++iter;\n            if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) {\n                appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00);\n            }\n            else {\n#ifdef GHC_RAISE_UNICODE_ERRORS\n                throw filesystem_error(\"Illegal code point for unicode character.\", result, std::make_error_code(std::errc::illegal_byte_sequence));\n#else\n                appendUTF8(result, 0xfffd);\n                if (iter == unicodeString.end()) {\n                    break;\n                }\n#endif\n            }\n        }\n        else {\n            appendUTF8(result, c);\n        }\n    }\n    return result;\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4>\ninline std::string toUtf8(const strT& unicodeString)\n{\n    std::string result;\n    for (auto c : unicodeString) {\n        appendUTF8(result, static_cast<uint32_t>(c));\n    }\n    return result;\n}\n\ntemplate <typename charT>\ninline std::string toUtf8(const charT* unicodeString)\n{\n#ifdef GHC_WITH_STRING_VIEW\n    return toUtf8(basic_string_view<charT, std::char_traits<charT>>(unicodeString));\n#else\n    return toUtf8(std::basic_string<charT, std::char_traits<charT>>(unicodeString));\n#endif\n}\n\n#ifdef GHC_USE_WCHAR_T\ntemplate <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false>\ninline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    auto temp = toUtf8(wString);\n    return StringType(temp.begin(), temp.end(), alloc);\n}\n\ntemplate <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false>\ninline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    return StringType(wString.begin(), wString.end(), alloc);\n}\n\ntemplate <class StringType, class WString, typename std::enable_if<path::_is_basic_string<WString>::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false>\ninline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type())\n{\n    auto temp = toUtf8(wString);\n    return fromUtf8<StringType>(temp, alloc);\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 1), bool>::type = false>\ninline std::wstring toWChar(const strT& unicodeString)\n{\n    return fromUtf8<std::wstring>(unicodeString);\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 2), bool>::type = false>\ninline std::wstring toWChar(const strT& unicodeString)\n{\n    return std::wstring(unicodeString.begin(), unicodeString.end());\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value && (sizeof(typename strT::value_type) == 4), bool>::type = false>\ninline std::wstring toWChar(const strT& unicodeString)\n{\n    auto temp = toUtf8(unicodeString);\n    return fromUtf8<std::wstring>(temp);\n}\n\ntemplate <typename charT>\ninline std::wstring toWChar(const charT* unicodeString)\n{\n#ifdef GHC_WITH_STRING_VIEW\n    return toWChar(basic_string_view<charT, std::char_traits<charT>>(unicodeString));\n#else\n    return toWChar(std::basic_string<charT, std::char_traits<charT>>(unicodeString));\n#endif\n}\n#endif // GHC_USE_WCHAR_T\n\n}  // namespace detail\n\n#ifdef GHC_EXPAND_IMPL\n\nnamespace detail {\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>\nGHC_INLINE bool startsWith(const strT& what, const strT& with)\n{\n    return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin());\n}\n\ntemplate <typename strT, typename std::enable_if<path::_is_basic_string<strT>::value, bool>::type = true>\nGHC_INLINE bool endsWith(const strT& what, const strT& with)\n{\n    return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0;\n}\n\n}  // namespace detail\n\nGHC_INLINE void path::check_long_path()\n{\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL(\"\\\\\\\\?\\\\\")))) {\n        postprocess_path_with_format(native_format);\n    }\n#endif\n}\n\nGHC_INLINE void path::postprocess_path_with_format(path::format fmt)\n{\n#ifdef GHC_RAISE_UNICODE_ERRORS\n    if (!detail::validUtf8(_path)) {\n        path t;\n        t._path = _path;\n        throw filesystem_error(\"Illegal byte sequence for unicode character.\", t, std::make_error_code(std::errc::illegal_byte_sequence));\n    }\n#endif\n    switch (fmt) {\n#ifdef GHC_OS_WINDOWS\n        case path::native_format:\n        case path::auto_format:\n        case path::generic_format:\n            for (auto& c : _path) {\n                if (c == generic_separator) {\n                    c = preferred_separator;\n                }\n            }\n#ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH\n            if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL(\"\\\\\\\\?\\\\\")))) {\n                _path = GHC_PLATFORM_LITERAL(\"\\\\\\\\?\\\\\") + _path;\n            }\n#endif\n            handle_prefixes();\n            break;\n#else\n        case path::auto_format:\n        case path::native_format:\n        case path::generic_format:\n            // nothing to do\n            break;\n#endif\n    }\n    if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) {\n        impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });\n        _path.erase(new_end, _path.end());\n    }\n    else {\n        impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast<string_type::difference_type>(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; });\n        _path.erase(new_end, _path.end());\n    }\n}\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <class Source, typename>\ninline path::path(const Source& source, format fmt)\n#ifdef GHC_USE_WCHAR_T\n    : _path(detail::toWChar(source))\n#else\n    : _path(detail::toUtf8(source))\n#endif\n{\n    postprocess_path_with_format(fmt);\n}\n\ntemplate <class Source, typename>\ninline path u8path(const Source& source)\n{\n    return path(source);\n}\ntemplate <class InputIterator>\ninline path u8path(InputIterator first, InputIterator last)\n{\n    return path(first, last);\n}\n\ntemplate <class InputIterator>\ninline path::path(InputIterator first, InputIterator last, format fmt)\n    : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)\n{\n    // delegated\n}\n\n#ifdef GHC_EXPAND_IMPL\n\nnamespace detail {\n\nGHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2)\n{\n#ifdef GHC_OS_WINDOWS\n#ifdef __GNUC__\n    while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) {\n        if (*str1++ == 0)\n            return true;\n    }\n    return false;\n#else // __GNUC__\n#ifdef GHC_USE_WCHAR_T\n    return 0 == ::_wcsicmp(str1, str2);\n#else // GHC_USE_WCHAR_T\n    return 0 == ::_stricmp(str1, str2);\n#endif // GHC_USE_WCHAR_T\n#endif // __GNUC__\n#else // GHC_OS_WINDOWS\n    return 0 == ::strcasecmp(str1, str2);\n#endif // GHC_OS_WINDOWS\n}\n\nGHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2)\n{\n    while (len1 > 0 && len2 > 0 && ::tolower(static_cast<unsigned char>(*str1)) == ::tolower(static_cast<unsigned char>(*str2))) {\n        --len1;\n        --len2;\n        ++str1;\n        ++str2;\n    }\n    if (len1 && len2) {\n        return *str1 < *str2 ? -1 : 1;\n    }\n    if (len1 == 0 && len2 == 0) {\n        return 0;\n    }\n    return len1 == 0 ? -1 : 1;\n}\n\nGHC_INLINE const char* strerror_adapter(char* gnu, char*)\n{\n    return gnu;\n}\n\nGHC_INLINE const char* strerror_adapter(int posix, char* buffer)\n{\n    if (posix) {\n        return \"Error in strerror_r!\";\n    }\n    return buffer;\n}\n\ntemplate <typename ErrorNumber>\nGHC_INLINE std::string systemErrorText(ErrorNumber code = 0)\n{\n#if defined(GHC_OS_WINDOWS)\n    LPVOID msgBuf;\n    DWORD dw = code ? static_cast<DWORD>(code) : ::GetLastError();\n    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL);\n    std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf));\n    LocalFree(msgBuf);\n    return msg;\n#else\n    char buffer[512];\n    return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer);\n#endif\n}\n\n#ifdef GHC_OS_WINDOWS\nusing CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD);\nusing CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);\n\nGHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)\n{\n    std::error_code tec;\n    auto fs = status(target_name, tec);\n    if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) {\n        ec = detail::make_error_code(detail::portable_error::not_supported);\n        return;\n    }\n#if defined(__GNUC__) && __GNUC__ >= 8\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-function-type\"\n#endif\n    static CreateSymbolicLinkW_fp api_call = reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(GetModuleHandleW(L\"kernel32.dll\"), \"CreateSymbolicLinkW\"));\n#if defined(__GNUC__) && __GNUC__ >= 8\n#pragma GCC diagnostic pop\n#endif\n    if (api_call) {\n        if (api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) {\n            auto result = ::GetLastError();\n            if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string()).c_str(), detail::fromUtf8<std::wstring>(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) {\n                return;\n            }\n            ec = detail::make_system_error(result);\n        }\n    }\n    else {\n        ec = detail::make_system_error(ERROR_NOT_SUPPORTED);\n    }\n}\n\nGHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)\n{\n#if defined(__GNUC__) && __GNUC__ >= 8\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-function-type\"\n#endif\n    static CreateHardLinkW_fp api_call = reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(GetModuleHandleW(L\"kernel32.dll\"), \"CreateHardLinkW\"));\n#if defined(__GNUC__) && __GNUC__ >= 8\n#pragma GCC diagnostic pop\n#endif\n    if (api_call) {\n        if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) {\n            ec = detail::make_system_error();\n        }\n    }\n    else {\n        ec = detail::make_system_error(ERROR_NOT_SUPPORTED);\n    }\n}\n\nGHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec)\n{\n    ULONG size = ::GetFullPathNameW(p, 0, 0, 0);\n    if (size) {\n        std::vector<wchar_t> buf(size, 0);\n        ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr);\n        if (s2 && s2 < size) {\n            return path(std::wstring(buf.data(), s2));\n        }\n    }\n    ec = detail::make_system_error();\n    return path();\n}\n\n#else\nGHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec)\n{\n    if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) {\n        ec = detail::make_system_error();\n    }\n}\n\n#ifndef GHC_OS_WEB\nGHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)\n{\n    if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) {\n        ec = detail::make_system_error();\n    }\n}\n#endif\n#endif\n\ntemplate <typename T>\nGHC_INLINE file_status file_status_from_st_mode(T mode)\n{\n#ifdef GHC_OS_WINDOWS\n    file_type ft = file_type::unknown;\n    if ((mode & _S_IFDIR) == _S_IFDIR) {\n        ft = file_type::directory;\n    }\n    else if ((mode & _S_IFREG) == _S_IFREG) {\n        ft = file_type::regular;\n    }\n    else if ((mode & _S_IFCHR) == _S_IFCHR) {\n        ft = file_type::character;\n    }\n    perms prms = static_cast<perms>(mode & 0xfff);\n    return file_status(ft, prms);\n#else\n    file_type ft = file_type::unknown;\n    if (S_ISDIR(mode)) {\n        ft = file_type::directory;\n    }\n    else if (S_ISREG(mode)) {\n        ft = file_type::regular;\n    }\n    else if (S_ISCHR(mode)) {\n        ft = file_type::character;\n    }\n    else if (S_ISBLK(mode)) {\n        ft = file_type::block;\n    }\n    else if (S_ISFIFO(mode)) {\n        ft = file_type::fifo;\n    }\n    else if (S_ISLNK(mode)) {\n        ft = file_type::symlink;\n    }\n    else if (S_ISSOCK(mode)) {\n        ft = file_type::socket;\n    }\n    perms prms = static_cast<perms>(mode & 0xfff);\n    return file_status(ft, prms);\n#endif\n}\n\nGHC_INLINE path resolveSymlink(const path& p, std::error_code& ec)\n{\n#ifdef GHC_OS_WINDOWS\n#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE\n    typedef struct _REPARSE_DATA_BUFFER\n    {\n        ULONG ReparseTag;\n        USHORT ReparseDataLength;\n        USHORT Reserved;\n        union\n        {\n            struct\n            {\n                USHORT SubstituteNameOffset;\n                USHORT SubstituteNameLength;\n                USHORT PrintNameOffset;\n                USHORT PrintNameLength;\n                ULONG Flags;\n                WCHAR PathBuffer[1];\n            } SymbolicLinkReparseBuffer;\n            struct\n            {\n                USHORT SubstituteNameOffset;\n                USHORT SubstituteNameLength;\n                USHORT PrintNameOffset;\n                USHORT PrintNameLength;\n                WCHAR PathBuffer[1];\n            } MountPointReparseBuffer;\n            struct\n            {\n                UCHAR DataBuffer[1];\n            } GenericReparseBuffer;\n        } DUMMYUNIONNAME;\n    } REPARSE_DATA_BUFFER;\n#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE\n#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)\n#endif\n#endif\n\n    std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);\n    if (file.get() == INVALID_HANDLE_VALUE) {\n        ec = detail::make_system_error();\n        return path();\n    }\n\n    std::shared_ptr<REPARSE_DATA_BUFFER> reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free);\n    ULONG bufferUsed;\n    path result;\n    if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) {\n        if (IsReparseTagMicrosoft(reparseData->ReparseTag)) {\n            switch (reparseData->ReparseTag) {\n                case IO_REPARSE_TAG_SYMLINK: {\n                    auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR));\n                    auto substituteName =\n                        std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR));\n                    if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L\"\\\\??\\\\\"))) {\n                        result = printName;\n                    }\n                    else {\n                        result = substituteName;\n                    }\n                    if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) {\n                        result = p.parent_path() / result;\n                    }\n                    break;\n                }\n                case IO_REPARSE_TAG_MOUNT_POINT:\n                    result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n    else {\n        ec = detail::make_system_error();\n    }\n    return result;\n#else\n    size_t bufferSize = 256;\n    while (true) {\n        std::vector<char> buffer(bufferSize, static_cast<char>(0));\n        auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size());\n        if (rc < 0) {\n            ec = detail::make_system_error();\n            return path();\n        }\n        else if (rc < static_cast<int>(bufferSize)) {\n            return path(std::string(buffer.data(), static_cast<std::string::size_type>(rc)));\n        }\n        bufferSize *= 2;\n    }\n    return path();\n#endif\n}\n\n#ifdef GHC_OS_WINDOWS\nGHC_INLINE time_t timeFromFILETIME(const FILETIME& ft)\n{\n    ULARGE_INTEGER ull;\n    ull.LowPart = ft.dwLowDateTime;\n    ull.HighPart = ft.dwHighDateTime;\n    return static_cast<time_t>(ull.QuadPart / 10000000ULL - 11644473600ULL);\n}\n\nGHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft)\n{\n    LONGLONG ll;\n    ll = Int32x32To64(t, 10000000) + 116444736000000000;\n    ft.dwLowDateTime = static_cast<DWORD>(ll);\n    ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);\n}\n\ntemplate <typename INFO>\nGHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info)\n{\n    return static_cast<uintmax_t>(-1);\n}\n\ntemplate <>\nGHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(const BY_HANDLE_FILE_INFORMATION* info)\n{\n    return info->nNumberOfLinks;\n}\n\ntemplate <typename INFO>\nGHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr)\n{\n    file_type ft = file_type::unknown;\n    if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n        ft = file_type::symlink;\n    }\n    else {\n        if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {\n            ft = file_type::directory;\n        }\n        else {\n            ft = file_type::regular;\n        }\n    }\n    perms prms = perms::owner_read | perms::group_read | perms::others_read;\n    if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {\n        prms = prms | perms::owner_write | perms::group_write | perms::others_write;\n    }\n    if (has_executable_extension(p)) {\n        prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec;\n    }\n    if (sz) {\n        *sz = static_cast<uintmax_t>(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow;\n    }\n    if (lwt) {\n        *lwt = detail::timeFromFILETIME(info->ftLastWriteTime);\n    }\n    return file_status(ft, prms);\n}\n\n#endif\n\nGHC_INLINE bool is_not_found_error(std::error_code& ec)\n{\n#ifdef GHC_OS_WINDOWS\n    return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME;\n#else\n    return ec.value() == ENOENT || ec.value() == ENOTDIR;\n#endif\n}\n\nGHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept\n{\n#ifdef GHC_OS_WINDOWS\n    file_status fs;\n    WIN32_FILE_ATTRIBUTE_DATA attr;\n    if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {\n        ec = detail::make_system_error();\n    }\n    else {\n        ec.clear();\n        fs = detail::status_from_INFO(p, &attr, ec, sz, lwt);\n        if (nhl) {\n            *nhl = 0;\n        }\n        if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {\n            fs.type(file_type::symlink);\n        }\n    }\n    if (detail::is_not_found_error(ec)) {\n        return file_status(file_type::not_found);\n    }\n    return ec ? file_status(file_type::none) : fs;\n#else\n    (void)sz;\n    (void)nhl;\n    (void)lwt;\n    struct ::stat fs;\n    auto result = ::lstat(p.c_str(), &fs);\n    if (result == 0) {\n        ec.clear();\n        file_status f_s = detail::file_status_from_st_mode(fs.st_mode);\n        return f_s;\n    }\n    ec = detail::make_system_error();\n    if (detail::is_not_found_error(ec)) {\n        return file_status(file_type::not_found, perms::unknown);\n    }\n    return file_status(file_type::none);\n#endif\n}\n\nGHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    if (recurse_count > 16) {\n        ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/);\n        return file_status(file_type::unknown);\n    }\n    WIN32_FILE_ATTRIBUTE_DATA attr;\n    if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {\n        ec = detail::make_system_error();\n    }\n    else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {\n        path target = resolveSymlink(p, ec);\n        file_status result;\n        if (!ec && !target.empty()) {\n            if (sls) {\n                *sls = status_from_INFO(p, &attr, ec);\n            }\n            return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1);\n        }\n        return file_status(file_type::unknown);\n    }\n    if (ec) {\n        if (detail::is_not_found_error(ec)) {\n            return file_status(file_type::not_found);\n        }\n        return file_status(file_type::none);\n    }\n    if (nhl) {\n        *nhl = 0;\n    }\n    return detail::status_from_INFO(p, &attr, ec, sz, lwt);\n#else\n    (void)recurse_count;\n    struct ::stat st;\n    auto result = ::lstat(p.c_str(), &st);\n    if (result == 0) {\n        ec.clear();\n        file_status fs = detail::file_status_from_st_mode(st.st_mode);\n        if (sls) {\n            *sls = fs;\n        }\n        if (fs.type() == file_type::symlink) {\n            result = ::stat(p.c_str(), &st);\n            if (result == 0) {\n                fs = detail::file_status_from_st_mode(st.st_mode);\n            }\n            else {\n                ec = detail::make_system_error();\n                if (detail::is_not_found_error(ec)) {\n                    return file_status(file_type::not_found, perms::unknown);\n                }\n                return file_status(file_type::none);\n            }\n        }\n        if (sz) {\n            *sz = static_cast<uintmax_t>(st.st_size);\n        }\n        if (nhl) {\n            *nhl = st.st_nlink;\n        }\n        if (lwt) {\n            *lwt = st.st_mtime;\n        }\n        return fs;\n    }\n    else {\n        ec = detail::make_system_error();\n        if (detail::is_not_found_error(ec)) {\n            return file_status(file_type::not_found, perms::unknown);\n        }\n        return file_status(file_type::none);\n    }\n#endif\n}\n\n}  // namespace detail\n\nGHC_INLINE u8arguments::u8arguments(int& argc, char**& argv)\n    : _argc(argc)\n    , _argv(argv)\n    , _refargc(argc)\n    , _refargv(argv)\n    , _isvalid(false)\n{\n#ifdef GHC_OS_WINDOWS\n    LPWSTR* p;\n    p = ::CommandLineToArgvW(::GetCommandLineW(), &argc);\n    _args.reserve(static_cast<size_t>(argc));\n    _argp.reserve(static_cast<size_t>(argc));\n    for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {\n        _args.push_back(detail::toUtf8(std::wstring(p[i])));\n        _argp.push_back((char*)_args[i].data());\n    }\n    argv = _argp.data();\n    ::LocalFree(p);\n    _isvalid = true;\n#else\n    std::setlocale(LC_ALL, \"\");\n#if defined(__ANDROID__) && __ANDROID_API__ < 26\n    _isvalid = true;\n#else\n    if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), \"UTF-8\")) {\n        _isvalid = true;\n    }\n#endif\n#endif\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.1 constructors and destructor\n\nGHC_INLINE path::path() noexcept {}\n\nGHC_INLINE path::path(const path& p)\n    : _path(p._path)\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    , _prefixLength(p._prefixLength)\n#endif\n{\n}\n\nGHC_INLINE path::path(path&& p) noexcept\n    : _path(std::move(p._path))\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    , _prefixLength(p._prefixLength)\n#endif\n{\n}\n\nGHC_INLINE path::path(string_type&& source, format fmt)\n    : _path(std::move(source))\n{\n    postprocess_path_with_format(fmt);\n}\n\n#endif  // GHC_EXPAND_IMPL\n\n#ifdef GHC_WITH_EXCEPTIONS\ntemplate <class Source, typename>\ninline path::path(const Source& source, const std::locale& loc, format fmt)\n    : path(source, fmt)\n{\n    std::string locName = loc.name();\n    if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == \"UTF-8\" || locName.substr(locName.length() - 5) == \"utf-8\"))) {\n        throw filesystem_error(\"This implementation only supports UTF-8 locales!\", path(_path), detail::make_error_code(detail::portable_error::not_supported));\n    }\n}\n\ntemplate <class InputIterator>\ninline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt)\n    : path(std::basic_string<typename std::iterator_traits<InputIterator>::value_type>(first, last), fmt)\n{\n    std::string locName = loc.name();\n    if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == \"UTF-8\" || locName.substr(locName.length() - 5) == \"utf-8\"))) {\n        throw filesystem_error(\"This implementation only supports UTF-8 locales!\", path(_path), detail::make_error_code(detail::portable_error::not_supported));\n    }\n}\n#endif\n\n#ifdef GHC_EXPAND_IMPL\n\nGHC_INLINE path::~path() {}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.2 assignments\n\nGHC_INLINE path& path::operator=(const path& p)\n{\n    _path = p._path;\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    _prefixLength = p._prefixLength;\n#endif\n    return *this;\n}\n\nGHC_INLINE path& path::operator=(path&& p) noexcept\n{\n    _path = std::move(p._path);\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    _prefixLength = p._prefixLength;\n#endif\n    return *this;\n}\n\nGHC_INLINE path& path::operator=(path::string_type&& source)\n{\n    return assign(source);\n}\n\nGHC_INLINE path& path::assign(path::string_type&& source)\n{\n    _path = std::move(source);\n    postprocess_path_with_format(native_format);\n    return *this;\n}\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <class Source>\ninline path& path::operator=(const Source& source)\n{\n    return assign(source);\n}\n\ntemplate <class Source>\ninline path& path::assign(const Source& source)\n{\n#ifdef GHC_USE_WCHAR_T\n    _path.assign(detail::toWChar(source));\n#else\n    _path.assign(detail::toUtf8(source));\n#endif\n    postprocess_path_with_format(native_format);\n    return *this;\n}\n\ntemplate <>\ninline path& path::assign<path>(const path& source)\n{\n    _path = source._path;\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    _prefixLength = source._prefixLength;\n#endif\n    return *this;\n}\n\ntemplate <class InputIterator>\ninline path& path::assign(InputIterator first, InputIterator last)\n{\n    _path.assign(first, last);\n    postprocess_path_with_format(native_format);\n    return *this;\n}\n\n#ifdef GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.3 appends\n\nGHC_INLINE path& path::operator/=(const path& p)\n{\n    if (p.empty()) {\n        // was: if ((!has_root_directory() && is_absolute()) || has_filename())\n        if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') {\n            _path += preferred_separator;\n        }\n        return *this;\n    }\n    if ((p.is_absolute() && (_path != root_name()._path || p._path != \"/\")) || (p.has_root_name() && p.root_name() != root_name())) {\n        assign(p);\n        return *this;\n    }\n    if (p.has_root_directory()) {\n        assign(root_name());\n    }\n    else if ((!has_root_directory() && is_absolute()) || has_filename()) {\n        _path += preferred_separator;\n    }\n    auto iter = p.begin();\n    bool first = true;\n    if (p.has_root_name()) {\n        ++iter;\n    }\n    while (iter != p.end()) {\n        if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) {\n            _path += preferred_separator;\n        }\n        first = false;\n        _path += (*iter++).native();\n    }\n    check_long_path();\n    return *this;\n}\n\nGHC_INLINE void path::append_name(const value_type* name)\n{\n    if (_path.empty()) {\n        this->operator/=(path(name));\n    }\n    else {\n        if (_path.back() != path::preferred_separator) {\n            _path.push_back(path::preferred_separator);\n        }\n        _path += name;\n        check_long_path();\n    }\n}\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <class Source>\ninline path& path::operator/=(const Source& source)\n{\n    return append(source);\n}\n\ntemplate <class Source>\ninline path& path::append(const Source& source)\n{\n    return this->operator/=(path(source));\n}\n\ntemplate <>\ninline path& path::append<path>(const path& p)\n{\n    return this->operator/=(p);\n}\n\ntemplate <class InputIterator>\ninline path& path::append(InputIterator first, InputIterator last)\n{\n    std::basic_string<typename std::iterator_traits<InputIterator>::value_type> part(first, last);\n    return append(part);\n}\n\n#ifdef GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.4 concatenation\n\nGHC_INLINE path& path::operator+=(const path& x)\n{\n    return concat(x._path);\n}\n\nGHC_INLINE path& path::operator+=(const string_type& x)\n{\n    return concat(x);\n}\n\n#ifdef GHC_WITH_STRING_VIEW\nGHC_INLINE path& path::operator+=(basic_string_view<value_type> x)\n{\n    return concat(x);\n}\n#endif\n\nGHC_INLINE path& path::operator+=(const value_type* x)\n{\n#ifdef GHC_WITH_STRING_VIEW\n    basic_string_view<value_type> part(x);\n#else\n    string_type part(x);\n#endif\n    return concat(part);\n}\n\nGHC_INLINE path& path::operator+=(value_type x)\n{\n#ifdef GHC_OS_WINDOWS\n    if (x == generic_separator) {\n        x = preferred_separator;\n    }\n#endif\n    if (_path.empty() || _path.back() != preferred_separator) {\n        _path += x;\n    }\n    check_long_path();\n    return *this;\n}\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <class Source>\ninline path::path_from_string<Source>& path::operator+=(const Source& x)\n{\n    return concat(x);\n}\n\ntemplate <class EcharT>\ninline path::path_type_EcharT<EcharT>& path::operator+=(EcharT x)\n{\n#ifdef GHC_WITH_STRING_VIEW\n    basic_string_view<EcharT> part(&x, 1);\n#else\n    std::basic_string<EcharT> part(1, x);\n#endif\n    concat(part);\n    return *this;\n}\n\ntemplate <class Source>\ninline path& path::concat(const Source& x)\n{\n    path p(x);\n    _path += p._path;\n    postprocess_path_with_format(native_format);\n    return *this;\n}\ntemplate <class InputIterator>\ninline path& path::concat(InputIterator first, InputIterator last)\n{\n    _path.append(first, last);\n    postprocess_path_with_format(native_format);\n    return *this;\n}\n\n#ifdef GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.5 modifiers\nGHC_INLINE void path::clear() noexcept\n{\n    _path.clear();\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    _prefixLength = 0;\n#endif\n}\n\nGHC_INLINE path& path::make_preferred()\n{\n    // as this filesystem implementation only uses generic_format\n    // internally, this must be a no-op\n    return *this;\n}\n\nGHC_INLINE path& path::remove_filename()\n{\n    if (has_filename()) {\n        _path.erase(_path.size() - filename()._path.size());\n    }\n    return *this;\n}\n\nGHC_INLINE path& path::replace_filename(const path& replacement)\n{\n    remove_filename();\n    return append(replacement);\n}\n\nGHC_INLINE path& path::replace_extension(const path& replacement)\n{\n    if (has_extension()) {\n        _path.erase(_path.size() - extension()._path.size());\n    }\n    if (!replacement.empty() && replacement._path[0] != '.') {\n        _path += '.';\n    }\n    return concat(replacement);\n}\n\nGHC_INLINE void path::swap(path& rhs) noexcept\n{\n    _path.swap(rhs._path);\n#if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    std::swap(_prefixLength, rhs._prefixLength);\n#endif\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.6, native format observers\nGHC_INLINE const path::string_type& path::native() const noexcept\n{\n    return _path;\n}\n\nGHC_INLINE const path::value_type* path::c_str() const noexcept\n{\n    return native().c_str();\n}\n\nGHC_INLINE path::operator path::string_type() const\n{\n    return native();\n}\n\n#endif  // GHC_EXPAND_IMPL\n\ntemplate <class EcharT, class traits, class Allocator>\ninline std::basic_string<EcharT, traits, Allocator> path::string(const Allocator& a) const\n{\n#ifdef GHC_USE_WCHAR_T\n    return detail::fromWChar<std::basic_string<EcharT, traits, Allocator>>(_path, a);\n#else\n    return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);\n#endif\n}\n\n#ifdef GHC_EXPAND_IMPL\n\nGHC_INLINE std::string path::string() const\n{\n#ifdef GHC_USE_WCHAR_T\n    return detail::toUtf8(native());\n#else\n    return native();\n#endif\n}\n\nGHC_INLINE std::wstring path::wstring() const\n{\n#ifdef GHC_USE_WCHAR_T\n    return native();\n#else\n    return detail::fromUtf8<std::wstring>(native());\n#endif\n}\n\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\nGHC_INLINE std::u8string path::u8string() const\n{\n#ifdef GHC_USE_WCHAR_T\n    return std::u8string(reinterpret_cast<const char8_t*>(detail::toUtf8(native()).c_str()));\n#else\n    return std::u8string(reinterpret_cast<const char8_t*>(c_str()));\n#endif\n}\n#else\nGHC_INLINE std::string path::u8string() const\n{\n#ifdef GHC_USE_WCHAR_T\n    return detail::toUtf8(native());\n#else\n    return native();\n#endif\n}\n#endif\n\nGHC_INLINE std::u16string path::u16string() const\n{\n    // TODO: optimize\n    return detail::fromUtf8<std::u16string>(string());\n}\n\nGHC_INLINE std::u32string path::u32string() const\n{\n    // TODO: optimize\n    return detail::fromUtf8<std::u32string>(string());\n}\n\n#endif  // GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.7, generic format observers\ntemplate <class EcharT, class traits, class Allocator>\ninline std::basic_string<EcharT, traits, Allocator> path::generic_string(const Allocator& a) const\n{\n#ifdef GHC_OS_WINDOWS\n#ifdef GHC_USE_WCHAR_T\n    auto result = detail::fromWChar<std::basic_string<EcharT, traits, Allocator>, path::string_type>(_path, a);\n#else\n    auto result = detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);\n#endif\n    for (auto& c : result) {\n        if (c == preferred_separator) {\n            c = generic_separator;\n        }\n    }\n    return result;\n#else\n    return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(_path, a);\n#endif\n}\n\n#ifdef GHC_EXPAND_IMPL\n\nGHC_INLINE std::string path::generic_string() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();\n#else\n    return _path;\n#endif\n}\n\nGHC_INLINE std::wstring path::generic_wstring() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::wstring::value_type, std::wstring::traits_type, std::wstring::allocator_type>();\n#else\n    return detail::fromUtf8<std::wstring>(_path);\n#endif\n}  // namespace filesystem\n\n#if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API)\nGHC_INLINE std::u8string path::generic_u8string() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::u8string::value_type, std::u8string::traits_type, std::u8string::allocator_type>();\n#else\n    return std::u8string(reinterpret_cast<const char8_t*>(_path.c_str()));\n#endif\n}\n#else\nGHC_INLINE std::string path::generic_u8string() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::string::value_type, std::string::traits_type, std::string::allocator_type>();\n#else\n    return _path;\n#endif\n}\n#endif\n\nGHC_INLINE std::u16string path::generic_u16string() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::u16string::value_type, std::u16string::traits_type, std::u16string::allocator_type>();\n#else\n    return detail::fromUtf8<std::u16string>(_path);\n#endif\n}\n\nGHC_INLINE std::u32string path::generic_u32string() const\n{\n#ifdef GHC_OS_WINDOWS\n    return generic_string<std::u32string::value_type, std::u32string::traits_type, std::u32string::allocator_type>();\n#else\n    return detail::fromUtf8<std::u32string>(_path);\n#endif\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.8, compare\nGHC_INLINE int path::compare(const path& p) const noexcept\n{\n#ifdef LWG_2936_BEHAVIOUR\n    auto rnl1 = root_name_length();\n    auto rnl2 = p.root_name_length();\n#ifdef GHC_OS_WINDOWS\n    auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);\n#else\n    auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2)));\n#endif\n    if (rnc) {\n        return rnc;\n    }\n    bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory();\n    if (hrd1 != hrd2) {\n        return hrd1 ? 1 : -1;\n    }\n    if (hrd1) {\n        ++rnl1;\n        ++rnl2;\n    }\n    auto iter1 = _path.begin() + static_cast<int>(rnl1);\n    auto iter2 = p._path.begin() + static_cast<int>(rnl2);\n    while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) {\n        ++iter1;\n        ++iter2;\n    }\n    if (iter1 == _path.end()) {\n        return iter2 == p._path.end() ? 0 : -1;\n    }\n    if (iter2 == p._path.end()) {\n        return 1;\n    }\n    if (*iter1 == preferred_separator) {\n        return -1;\n    }\n    if (*iter2 == preferred_separator) {\n        return 1;\n    }\n    return *iter1 < *iter2 ? -1 : 1;\n#else  // LWG_2936_BEHAVIOUR\n#ifdef GHC_OS_WINDOWS\n    auto rnl1 = root_name_length();\n    auto rnl2 = p.root_name_length();\n    auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2);\n    if (rnc) {\n        return rnc;\n    }\n    return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos);\n#else\n    return _path.compare(p._path);\n#endif\n#endif\n}\n\nGHC_INLINE int path::compare(const string_type& s) const\n{\n    return compare(path(s));\n}\n\n#ifdef GHC_WITH_STRING_VIEW\nGHC_INLINE int path::compare(basic_string_view<value_type> s) const\n{\n    return compare(path(s));\n}\n#endif\n\nGHC_INLINE int path::compare(const value_type* s) const\n{\n    return compare(path(s));\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.9, decomposition\n#ifdef GHC_OS_WINDOWS\nGHC_INLINE void path::handle_prefixes()\n{\n#if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH)\n    _prefixLength = 0;\n    if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast<unsigned char>(_path[4])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[4])) <= 'Z' && _path[5] == ':') {\n        if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL(\"\\\\\\\\?\\\\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL(\"\\\\??\\\\\")))) {\n            _prefixLength = 4;\n        }\n    }\n#endif  // GHC_WIN_AUTO_PREFIX_LONG_PATH\n}\n#endif\n\nGHC_INLINE path::string_type::size_type path::root_name_length() const noexcept\n{\n#ifdef GHC_OS_WINDOWS\n    if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) >= 'A' && std::toupper(static_cast<unsigned char>(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') {\n        return 2;\n    }\n#endif\n    if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) {\n        impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3);\n        if (pos == impl_string_type::npos) {\n            return _path.length();\n        }\n        else {\n            return pos;\n        }\n    }\n    return 0;\n}\n\nGHC_INLINE path path::root_name() const\n{\n    return path(_path.substr(_prefixLength, root_name_length()), native_format);\n}\n\nGHC_INLINE path path::root_directory() const\n{\n    if (has_root_directory()) {\n        static const path _root_dir(std::string(1, preferred_separator), native_format);\n        return _root_dir;\n    }\n    return path();\n}\n\nGHC_INLINE path path::root_path() const\n{\n    return path(root_name().string() + root_directory().string(), native_format);\n}\n\nGHC_INLINE path path::relative_path() const\n{\n    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);\n    return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format);\n}\n\nGHC_INLINE path path::parent_path() const\n{\n    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);\n    if (rootPathLen < _path.length()) {\n        if (empty()) {\n            return path();\n        }\n        else {\n            auto piter = end();\n            auto iter = piter.decrement(_path.end());\n            if (iter > _path.begin() + static_cast<long>(rootPathLen) && *iter != preferred_separator) {\n                --iter;\n            }\n            return path(_path.begin(), iter, native_format);\n        }\n    }\n    else {\n        return *this;\n    }\n}\n\nGHC_INLINE path path::filename() const\n{\n    return !has_relative_path() ? path() : path(*--end());\n}\n\nGHC_INLINE path path::stem() const\n{\n    impl_string_type fn = filename().native();\n    if (fn != \".\" && fn != \"..\") {\n        impl_string_type::size_type pos = fn.rfind('.');\n        if (pos != impl_string_type::npos && pos > 0) {\n            return path{fn.substr(0, pos), native_format};\n        }\n    }\n    return path{fn, native_format};\n}\n\nGHC_INLINE path path::extension() const\n{\n    if (has_relative_path()) {\n        auto iter = end();\n        const auto& fn = *--iter;\n        impl_string_type::size_type pos = fn._path.rfind('.');\n        if (pos != std::string::npos && pos > 0) {\n            return path(fn._path.substr(pos), native_format);\n        }\n    }\n    return path();\n}\n\n#ifdef GHC_OS_WINDOWS\nnamespace detail {\nGHC_INLINE bool has_executable_extension(const path& p)\n{\n    if (p.has_relative_path()) {\n        auto iter = p.end();\n        const auto& fn = *--iter;\n        auto pos = fn._path.find_last_of('.');\n        if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) {\n            return false;\n        }\n        const path::value_type* ext = fn._path.c_str() + pos + 1;\n        if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL(\"exe\")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL(\"cmd\")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL(\"bat\")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL(\"com\"))) {\n            return true;\n        }\n    }\n    return false;\n}\n}  // namespace detail\n#endif\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.10, query\nGHC_INLINE bool path::empty() const noexcept\n{\n    return _path.empty();\n}\n\nGHC_INLINE bool path::has_root_name() const\n{\n    return root_name_length() > 0;\n}\n\nGHC_INLINE bool path::has_root_directory() const\n{\n    auto rootLen = _prefixLength + root_name_length();\n    return (_path.length() > rootLen && _path[rootLen] == preferred_separator);\n}\n\nGHC_INLINE bool path::has_root_path() const\n{\n    return has_root_name() || has_root_directory();\n}\n\nGHC_INLINE bool path::has_relative_path() const\n{\n    auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0);\n    return rootPathLen < _path.length();\n}\n\nGHC_INLINE bool path::has_parent_path() const\n{\n    return !parent_path().empty();\n}\n\nGHC_INLINE bool path::has_filename() const\n{\n    return has_relative_path() && !filename().empty();\n}\n\nGHC_INLINE bool path::has_stem() const\n{\n    return !stem().empty();\n}\n\nGHC_INLINE bool path::has_extension() const\n{\n    return !extension().empty();\n}\n\nGHC_INLINE bool path::is_absolute() const\n{\n#ifdef GHC_OS_WINDOWS\n    return has_root_name() && has_root_directory();\n#else\n    return has_root_directory();\n#endif\n}\n\nGHC_INLINE bool path::is_relative() const\n{\n    return !is_absolute();\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.4.11, generation\nGHC_INLINE path path::lexically_normal() const\n{\n    path dest;\n    bool lastDotDot = false;\n    for (string_type s : *this) {\n        if (s == \".\") {\n            dest /= \"\";\n            continue;\n        }\n        else if (s == \"..\" && !dest.empty()) {\n            auto root = root_path();\n            if (dest == root) {\n                continue;\n            }\n            else if (*(--dest.end()) != \"..\") {\n                if (dest._path.back() == preferred_separator) {\n                    dest._path.pop_back();\n                }\n                dest.remove_filename();\n                continue;\n            }\n        }\n        if (!(s.empty() && lastDotDot)) {\n            dest /= s;\n        }\n        lastDotDot = s == \"..\";\n    }\n    if (dest.empty()) {\n        dest = \".\";\n    }\n    return dest;\n}\n\nGHC_INLINE path path::lexically_relative(const path& base) const\n{\n    if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) {\n        return path();\n    }\n    const_iterator a = begin(), b = base.begin();\n    while (a != end() && b != base.end() && *a == *b) {\n        ++a;\n        ++b;\n    }\n    if (a == end() && b == base.end()) {\n        return path(\".\");\n    }\n    int count = 0;\n    for (const auto& element : input_iterator_range<const_iterator>(b, base.end())) {\n        if (element != \".\" && element != \"\" && element != \"..\") {\n            ++count;\n        }\n        else if (element == \"..\") {\n            --count;\n        }\n    }\n    if (count < 0) {\n        return path();\n    }\n    path result;\n    for (int i = 0; i < count; ++i) {\n        result /= \"..\";\n    }\n    for (const auto& element : input_iterator_range<const_iterator>(a, end())) {\n        result /= element;\n    }\n    return result;\n}\n\nGHC_INLINE path path::lexically_proximate(const path& base) const\n{\n    path result = lexically_relative(base);\n    return result.empty() ? *this : result;\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.5, iterators\nGHC_INLINE path::iterator::iterator() {}\n\nGHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos)\n    : _first(p._path.begin())\n    , _last(p._path.end())\n    , _prefix(_first + static_cast<string_type::difference_type>(p._prefixLength))\n    , _root(p.has_root_directory() ? _first + static_cast<string_type::difference_type>(p._prefixLength + p.root_name_length()) : _last)\n    , _iter(pos)\n{\n    if(pos != _last) {\n        updateCurrent();\n    }\n}\n\nGHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const\n{\n    path::impl_string_type::const_iterator i = pos;\n    bool fromStart = i == _first || i == _prefix;\n    if (i != _last) {\n        if (fromStart && i == _first && _prefix > _first) {\n            i = _prefix;\n        }\n        else if (*i++ == preferred_separator) {\n            // we can only sit on a slash if it is a network name or a root\n            if (i != _last && *i == preferred_separator) {\n                if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) {\n                    // leadind double slashes detected, treat this and the\n                    // following until a slash as one unit\n                    i = std::find(++i, _last, preferred_separator);\n                }\n                else {\n                    // skip redundant slashes\n                    while (i != _last && *i == preferred_separator) {\n                        ++i;\n                    }\n                }\n            }\n        }\n        else {\n            if (fromStart && i != _last && *i == ':') {\n                ++i;\n            }\n            else {\n                i = std::find(i, _last, preferred_separator);\n            }\n        }\n    }\n    return i;\n}\n\nGHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const\n{\n    path::impl_string_type::const_iterator i = pos;\n    if (i != _first) {\n        --i;\n        // if this is now the root slash or the trailing slash, we are done,\n        // else check for network name\n        if (i != _root && (pos != _last || *i != preferred_separator)) {\n#ifdef GHC_OS_WINDOWS\n            static const impl_string_type seps = GHC_PLATFORM_LITERAL(\"\\\\:\");\n            i = std::find_first_of(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), seps.begin(), seps.end()).base();\n            if (i > _first && *i == ':') {\n                i++;\n            }\n#else\n            i = std::find(std::reverse_iterator<path::impl_string_type::const_iterator>(i), std::reverse_iterator<path::impl_string_type::const_iterator>(_first), preferred_separator).base();\n#endif\n            // Now we have to check if this is a network name\n            if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) {\n                i -= 2;\n            }\n        }\n    }\n    return i;\n}\n\nGHC_INLINE void path::iterator::updateCurrent()\n{\n    if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) {\n        _current.clear();\n    }\n    else {\n        _current.assign(_iter, increment(_iter));\n    }\n}\n\nGHC_INLINE path::iterator& path::iterator::operator++()\n{\n    _iter = increment(_iter);\n    while (_iter != _last &&                // we didn't reach the end\n           _iter != _root &&                // this is not a root position\n           *_iter == preferred_separator &&  // we are on a separator\n           (_iter + 1) != _last             // the slash is not the last char\n    ) {\n        ++_iter;\n    }\n    updateCurrent();\n    return *this;\n}\n\nGHC_INLINE path::iterator path::iterator::operator++(int)\n{\n    path::iterator i{*this};\n    ++(*this);\n    return i;\n}\n\nGHC_INLINE path::iterator& path::iterator::operator--()\n{\n    _iter = decrement(_iter);\n    updateCurrent();\n    return *this;\n}\n\nGHC_INLINE path::iterator path::iterator::operator--(int)\n{\n    auto i = *this;\n    --(*this);\n    return i;\n}\n\nGHC_INLINE bool path::iterator::operator==(const path::iterator& other) const\n{\n    return _iter == other._iter;\n}\n\nGHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const\n{\n    return _iter != other._iter;\n}\n\nGHC_INLINE path::iterator::reference path::iterator::operator*() const\n{\n    return _current;\n}\n\nGHC_INLINE path::iterator::pointer path::iterator::operator->() const\n{\n    return &_current;\n}\n\nGHC_INLINE path::iterator path::begin() const\n{\n    return iterator(*this, _path.begin());\n}\n\nGHC_INLINE path::iterator path::end() const\n{\n    return iterator(*this, _path.end());\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.8.6, path non-member functions\nGHC_INLINE void swap(path& lhs, path& rhs) noexcept\n{\n    swap(lhs._path, rhs._path);\n}\n\nGHC_INLINE size_t hash_value(const path& p) noexcept\n{\n    return std::hash<std::string>()(p.generic_string());\n}\n\n#ifdef GHC_HAS_THREEWAY_COMP\nGHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) <=> 0;\n}\n#endif\n\nGHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) == 0;\n}\n\nGHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept\n{\n    return !(lhs == rhs);\n}\n\nGHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) < 0;\n}\n\nGHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) <= 0;\n}\n\nGHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) > 0;\n}\n\nGHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept\n{\n    return lhs.compare(rhs) >= 0;\n}\n\nGHC_INLINE path operator/(const path& lhs, const path& rhs)\n{\n    path result(lhs);\n    result /= rhs;\n    return result;\n}\n\n#endif  // GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.8.6.1 path inserter and extractor\ntemplate <class charT, class traits>\ninline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const path& p)\n{\n    os << \"\\\"\";\n    auto ps = p.string<charT, traits>();\n    for (auto c : ps) {\n        if (c == '\"' || c == '\\\\') {\n            os << '\\\\';\n        }\n        os << c;\n    }\n    os << \"\\\"\";\n    return os;\n}\n\ntemplate <class charT, class traits>\ninline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, path& p)\n{\n    std::basic_string<charT, traits> tmp;\n    charT c;\n    is >> c;\n    if (c == '\"') {\n        auto sf = is.flags();\n        is >> std::noskipws;\n        while (is) {\n            auto c2 = is.get();\n            if (is) {\n                if (c2 == '\\\\') {\n                    c2 = is.get();\n                    if (is) {\n                        tmp += static_cast<charT>(c2);\n                    }\n                }\n                else if (c2 == '\"') {\n                    break;\n                }\n                else {\n                    tmp += static_cast<charT>(c2);\n                }\n            }\n        }\n        if ((sf & std::ios_base::skipws) == std::ios_base::skipws) {\n            is >> std::skipws;\n        }\n        p = path(tmp);\n    }\n    else {\n        is >> tmp;\n        p = path(static_cast<charT>(c) + tmp);\n    }\n    return is;\n}\n\n#ifdef GHC_EXPAND_IMPL\n\n//-----------------------------------------------------------------------------\n// 30.10.9 Class filesystem_error\nGHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec)\n    : std::system_error(ec, what_arg)\n    , _what_arg(what_arg)\n    , _ec(ec)\n{\n}\n\nGHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec)\n    : std::system_error(ec, what_arg)\n    , _what_arg(what_arg)\n    , _ec(ec)\n    , _p1(p1)\n{\n    if (!_p1.empty()) {\n        _what_arg += \": '\" + _p1.string() + \"'\";\n    }\n}\n\nGHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec)\n    : std::system_error(ec, what_arg)\n    , _what_arg(what_arg)\n    , _ec(ec)\n    , _p1(p1)\n    , _p2(p2)\n{\n    if (!_p1.empty()) {\n        _what_arg += \": '\" + _p1.string() + \"'\";\n    }\n    if (!_p2.empty()) {\n        _what_arg += \", '\" + _p2.string() + \"'\";\n    }\n}\n\nGHC_INLINE const path& filesystem_error::path1() const noexcept\n{\n    return _p1;\n}\n\nGHC_INLINE const path& filesystem_error::path2() const noexcept\n{\n    return _p2;\n}\n\nGHC_INLINE const char* filesystem_error::what() const noexcept\n{\n    return _what_arg.c_str();\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.15, filesystem operations\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path absolute(const path& p)\n{\n    std::error_code ec;\n    path result = absolute(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path absolute(const path& p, std::error_code& ec)\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    if (p.empty()) {\n        return absolute(current_path(ec), ec) / \"\";\n    }\n    ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0);\n    if (size) {\n        std::vector<wchar_t> buf(size, 0);\n        ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr);\n        if (s2 && s2 < size) {\n            path result = path(std::wstring(buf.data(), s2));\n            if (p.filename() == \".\") {\n                result /= \".\";\n            }\n            return result;\n        }\n    }\n    ec = detail::make_system_error();\n    return path();\n#else\n    path base = current_path(ec);\n    if (!ec) {\n        if (p.empty()) {\n            return base / p;\n        }\n        if (p.has_root_name()) {\n            if (p.has_root_directory()) {\n                return p;\n            }\n            else {\n                return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path();\n            }\n        }\n        else {\n            if (p.has_root_directory()) {\n                return base.root_name() / p;\n            }\n            else {\n                return base / p;\n            }\n        }\n    }\n    ec = detail::make_system_error();\n    return path();\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path canonical(const path& p)\n{\n    std::error_code ec;\n    auto result = canonical(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path canonical(const path& p, std::error_code& ec)\n{\n    if (p.empty()) {\n        ec = detail::make_error_code(detail::portable_error::not_found);\n        return path();\n    }\n    path work = p.is_absolute() ? p : absolute(p, ec);\n    path result;\n\n    auto fs = status(work, ec);\n    if (ec) {\n        return path();\n    }\n    if (fs.type() == file_type::not_found) {\n        ec = detail::make_error_code(detail::portable_error::not_found);\n        return path();\n    }\n    bool redo;\n    do {\n        auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0);\n        redo = false;\n        result.clear();\n        for (auto pe : work) {\n            if (pe.empty() || pe == \".\") {\n                continue;\n            }\n            else if (pe == \"..\") {\n                result = result.parent_path();\n                continue;\n            }\n            else if ((result / pe).string().length() <= rootPathLen) {\n                result /= pe;\n                continue;\n            }\n            auto sls = symlink_status(result / pe, ec);\n            if (ec) {\n                return path();\n            }\n            if (is_symlink(sls)) {\n                redo = true;\n                auto target = read_symlink(result / pe, ec);\n                if (ec) {\n                    return path();\n                }\n                if (target.is_absolute()) {\n                    result = target;\n                    continue;\n                }\n                else {\n                    result /= target;\n                    continue;\n                }\n            }\n            else {\n                result /= pe;\n            }\n        }\n        work = result;\n    } while (redo);\n    ec.clear();\n    return result;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void copy(const path& from, const path& to)\n{\n    copy(from, to, copy_options::none);\n}\n\nGHC_INLINE void copy(const path& from, const path& to, copy_options options)\n{\n    std::error_code ec;\n    copy(from, to, options, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);\n    }\n}\n#endif\n\nGHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept\n{\n    copy(from, to, copy_options::none, ec);\n}\n\nGHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept\n{\n    std::error_code tec;\n    file_status fs_from, fs_to;\n    ec.clear();\n    if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) {\n        fs_from = symlink_status(from, ec);\n    }\n    else {\n        fs_from = status(from, ec);\n    }\n    if (!exists(fs_from)) {\n        if (!ec) {\n            ec = detail::make_error_code(detail::portable_error::not_found);\n        }\n        return;\n    }\n    if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) {\n        fs_to = symlink_status(to, tec);\n    }\n    else {\n        fs_to = status(to, tec);\n    }\n    if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) {\n        ec = detail::make_error_code(detail::portable_error::invalid_argument);\n    }\n    else if (is_symlink(fs_from)) {\n        if ((options & copy_options::skip_symlinks) == copy_options::none) {\n            if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) {\n                copy_symlink(from, to, ec);\n            }\n            else {\n                ec = detail::make_error_code(detail::portable_error::invalid_argument);\n            }\n        }\n    }\n    else if (is_regular_file(fs_from)) {\n        if ((options & copy_options::directories_only) == copy_options::none) {\n            if ((options & copy_options::create_symlinks) != copy_options::none) {\n                create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec);\n            }\n#ifndef GHC_OS_WEB\n            else if ((options & copy_options::create_hard_links) != copy_options::none) {\n                create_hard_link(from, to, ec);\n            }\n#endif\n            else if (is_directory(fs_to)) {\n                copy_file(from, to / from.filename(), options, ec);\n            }\n            else {\n                copy_file(from, to, options, ec);\n            }\n        }\n    }\n#ifdef LWG_2682_BEHAVIOUR\n    else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) {\n        ec = detail::make_error_code(detail::portable_error::is_a_directory);\n    }\n#endif\n    else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) {\n        if (!exists(fs_to)) {\n            create_directory(to, from, ec);\n            if (ec) {\n                return;\n            }\n        }\n        for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) {\n            if (!ec) {\n                copy(iter->path(), to / iter->path().filename(), options | static_cast<copy_options>(0x8000), ec);\n            }\n            if (ec) {\n                return;\n            }\n        }\n    }\n    return;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool copy_file(const path& from, const path& to)\n{\n    return copy_file(from, to, copy_options::none);\n}\n\nGHC_INLINE bool copy_file(const path& from, const path& to, copy_options option)\n{\n    std::error_code ec;\n    auto result = copy_file(from, to, option, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept\n{\n    return copy_file(from, to, copy_options::none, ec);\n}\n\nGHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept\n{\n    std::error_code tecf, tect;\n    auto sf = status(from, tecf);\n    auto st = status(to, tect);\n    bool overwrite = false;\n    ec.clear();\n    if (!is_regular_file(sf)) {\n        ec = tecf;\n        return false;\n    }\n    if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) {\n        ec = tect ? tect : detail::make_error_code(detail::portable_error::exists);\n        return false;\n    }\n    if (exists(st)) {\n        if ((options & copy_options::update_existing) == copy_options::update_existing) {\n            auto from_time = last_write_time(from, ec);\n            if (ec) {\n                ec = detail::make_system_error();\n                return false;\n            }\n            auto to_time = last_write_time(to, ec);\n            if (ec) {\n                ec = detail::make_system_error();\n                return false;\n            }\n            if (from_time <= to_time) {\n                return false;\n            }\n        }\n        overwrite = true;\n    }\n#ifdef GHC_OS_WINDOWS\n    if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) {\n        ec = detail::make_system_error();\n        return false;\n    }\n    return true;\n#else\n    std::vector<char> buffer(16384, '\\0');\n    int in = -1, out = -1;\n    if ((in = ::open(from.c_str(), O_RDONLY)) < 0) {\n        ec = detail::make_system_error();\n        return false;\n    }\n    int mode = O_CREAT | O_WRONLY | O_TRUNC;\n    if (!overwrite) {\n        mode |= O_EXCL;\n    }\n    if ((out = ::open(to.c_str(), mode, static_cast<int>(sf.permissions() & perms::all))) < 0) {\n        ec = detail::make_system_error();\n        ::close(in);\n        return false;\n    }\n    ssize_t br, bw;\n    while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {\n        ssize_t offset = 0;\n        do {\n            if ((bw = ::write(out, buffer.data() + offset, static_cast<size_t>(br))) > 0) {\n                br -= bw;\n                offset += bw;\n            }\n            else if (bw < 0) {\n                ec = detail::make_system_error();\n                ::close(in);\n                ::close(out);\n                return false;\n            }\n        } while (br);\n    }\n    ::close(in);\n    ::close(out);\n    return true;\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink)\n{\n    std::error_code ec;\n    copy_symlink(existing_symlink, new_symlink, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec);\n    }\n}\n#endif\n\nGHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept\n{\n    ec.clear();\n    auto to = read_symlink(existing_symlink, ec);\n    if (!ec) {\n        if (exists(to, ec) && is_directory(to, ec)) {\n            create_directory_symlink(to, new_symlink, ec);\n        }\n        else {\n            create_symlink(to, new_symlink, ec);\n        }\n    }\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool create_directories(const path& p)\n{\n    std::error_code ec;\n    auto result = create_directories(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept\n{\n    path current;\n    ec.clear();\n    bool didCreate = false;\n    for (path::string_type part : p) {\n        current /= part;\n        if (current != p.root_name() && current != p.root_path()) {\n            std::error_code tec;\n            auto fs = status(current, tec);\n            if (tec && fs.type() != file_type::not_found) {\n                ec = tec;\n                return false;\n            }\n            if (!exists(fs)) {\n                create_directory(current, ec);\n                if (ec) {\n                    std::error_code tmp_ec;\n                    if (is_directory(current, tmp_ec)) {\n                        ec.clear();\n                    }\n                    else {\n                        return false;\n                    }\n                }\n                didCreate = true;\n            }\n#ifndef LWG_2935_BEHAVIOUR\n            else if (!is_directory(fs)) {\n                ec = detail::make_error_code(detail::portable_error::exists);\n                return false;\n            }\n#endif\n        }\n    }\n    return didCreate;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool create_directory(const path& p)\n{\n    std::error_code ec;\n    auto result = create_directory(p, path(), ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept\n{\n    return create_directory(p, path(), ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool create_directory(const path& p, const path& attributes)\n{\n    std::error_code ec;\n    auto result = create_directory(p, attributes, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept\n{\n    std::error_code tec;\n    ec.clear();\n    auto fs = status(p, tec);\n#ifdef LWG_2935_BEHAVIOUR\n    if (status_known(fs) && exists(fs)) {\n        return false;\n    }\n#else\n    if (status_known(fs) && exists(fs) && is_directory(fs)) {\n        return false;\n    }\n#endif\n#ifdef GHC_OS_WINDOWS\n    if (!attributes.empty()) {\n        if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) {\n            ec = detail::make_system_error();\n            return false;\n        }\n    }\n    else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) {\n        ec = detail::make_system_error();\n        return false;\n    }\n#else\n    ::mode_t attribs = static_cast<mode_t>(perms::all);\n    if (!attributes.empty()) {\n        struct ::stat fileStat;\n        if (::stat(attributes.c_str(), &fileStat) != 0) {\n            ec = detail::make_system_error();\n            return false;\n        }\n        attribs = fileStat.st_mode;\n    }\n    if (::mkdir(p.c_str(), attribs) != 0) {\n        ec = detail::make_system_error();\n        return false;\n    }\n#endif\n    return true;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink)\n{\n    std::error_code ec;\n    create_directory_symlink(to, new_symlink, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);\n    }\n}\n#endif\n\nGHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept\n{\n    detail::create_symlink(to, new_symlink, true, ec);\n}\n\n#ifndef GHC_OS_WEB\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void create_hard_link(const path& to, const path& new_hard_link)\n{\n    std::error_code ec;\n    create_hard_link(to, new_hard_link, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec);\n    }\n}\n#endif\n\nGHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept\n{\n    detail::create_hardlink(to, new_hard_link, ec);\n}\n#endif\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void create_symlink(const path& to, const path& new_symlink)\n{\n    std::error_code ec;\n    create_symlink(to, new_symlink, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec);\n    }\n}\n#endif\n\nGHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept\n{\n    detail::create_symlink(to, new_symlink, false, ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path current_path()\n{\n    std::error_code ec;\n    auto result = current_path(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path current_path(std::error_code& ec)\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    DWORD pathlen = ::GetCurrentDirectoryW(0, 0);\n    std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]);\n    if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) {\n        ec = detail::make_system_error();\n        return path();\n    }\n    return path(std::wstring(buffer.get()), path::native_format);\n#else\n    size_t pathlen = static_cast<size_t>(std::max(int(::pathconf(\".\", _PC_PATH_MAX)), int(PATH_MAX)));\n    std::unique_ptr<char[]> buffer(new char[pathlen + 1]);\n    if (::getcwd(buffer.get(), pathlen) == nullptr) {\n        ec = detail::make_system_error();\n        return path();\n    }\n    return path(buffer.get());\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void current_path(const path& p)\n{\n    std::error_code ec;\n    current_path(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n}\n#endif\n\nGHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) {\n        ec = detail::make_system_error();\n    }\n#else\n    if (::chdir(p.string().c_str()) == -1) {\n        ec = detail::make_system_error();\n    }\n#endif\n}\n\nGHC_INLINE bool exists(file_status s) noexcept\n{\n    return status_known(s) && s.type() != file_type::not_found;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool exists(const path& p)\n{\n    return exists(status(p));\n}\n#endif\n\nGHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept\n{\n    file_status s = status(p, ec);\n    if (status_known(s)) {\n        ec.clear();\n    }\n    return exists(s);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool equivalent(const path& p1, const path& p2)\n{\n    std::error_code ec;\n    bool result = equivalent(p1, p2, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    std::shared_ptr<void> file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);\n    auto e1 = ::GetLastError();\n    std::shared_ptr<void> file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);\n    if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) {\n#ifdef LWG_2937_BEHAVIOUR\n        ec = detail::make_system_error(e1 ? e1 : ::GetLastError());\n#else\n        if (file1 == file2) {\n            ec = detail::make_system_error(e1 ? e1 : ::GetLastError());\n        }\n#endif\n        return false;\n    }\n    BY_HANDLE_FILE_INFORMATION inf1, inf2;\n    if (!::GetFileInformationByHandle(file1.get(), &inf1)) {\n        ec = detail::make_system_error();\n        return false;\n    }\n    if (!::GetFileInformationByHandle(file2.get(), &inf2)) {\n        ec = detail::make_system_error();\n        return false;\n    }\n    return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow &&\n           inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber;\n#else\n    struct ::stat s1, s2;\n    auto rc1 = ::stat(p1.c_str(), &s1);\n    auto e1 = errno;\n    auto rc2 = ::stat(p2.c_str(), &s2);\n    if (rc1 || rc2) {\n#ifdef LWG_2937_BEHAVIOUR\n        ec = detail::make_system_error(e1 ? e1 : errno);\n#else\n        if (rc1 && rc2) {\n            ec = detail::make_system_error(e1 ? e1 : errno);\n        }\n#endif\n        return false;\n    }\n    return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE uintmax_t file_size(const path& p)\n{\n    std::error_code ec;\n    auto result = file_size(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    WIN32_FILE_ATTRIBUTE_DATA attr;\n    if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) {\n        ec = detail::make_system_error();\n        return static_cast<uintmax_t>(-1);\n    }\n    return static_cast<uintmax_t>(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow;\n#else\n    struct ::stat fileStat;\n    if (::stat(p.c_str(), &fileStat) == -1) {\n        ec = detail::make_system_error();\n        return static_cast<uintmax_t>(-1);\n    }\n    return static_cast<uintmax_t>(fileStat.st_size);\n#endif\n}\n\n#ifndef GHC_OS_WEB\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE uintmax_t hard_link_count(const path& p)\n{\n    std::error_code ec;\n    auto result = hard_link_count(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    uintmax_t result = static_cast<uintmax_t>(-1);\n    std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle);\n    BY_HANDLE_FILE_INFORMATION inf;\n    if (file.get() == INVALID_HANDLE_VALUE) {\n        ec = detail::make_system_error();\n    }\n    else {\n        if (!::GetFileInformationByHandle(file.get(), &inf)) {\n            ec = detail::make_system_error();\n        }\n        else {\n            result = inf.nNumberOfLinks;\n        }\n    }\n    return result;\n#else\n    uintmax_t result = 0;\n    file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr);\n    if (fs.type() == file_type::not_found) {\n        ec = detail::make_error_code(detail::portable_error::not_found);\n    }\n    return ec ? static_cast<uintmax_t>(-1) : result;\n#endif\n}\n#endif\n\nGHC_INLINE bool is_block_file(file_status s) noexcept\n{\n    return s.type() == file_type::block;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_block_file(const path& p)\n{\n    return is_block_file(status(p));\n}\n#endif\n\nGHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept\n{\n    return is_block_file(status(p, ec));\n}\n\nGHC_INLINE bool is_character_file(file_status s) noexcept\n{\n    return s.type() == file_type::character;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_character_file(const path& p)\n{\n    return is_character_file(status(p));\n}\n#endif\n\nGHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept\n{\n    return is_character_file(status(p, ec));\n}\n\nGHC_INLINE bool is_directory(file_status s) noexcept\n{\n    return s.type() == file_type::directory;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_directory(const path& p)\n{\n    return is_directory(status(p));\n}\n#endif\n\nGHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept\n{\n    return is_directory(status(p, ec));\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_empty(const path& p)\n{\n    if (is_directory(p)) {\n        return directory_iterator(p) == directory_iterator();\n    }\n    else {\n        return file_size(p) == 0;\n    }\n}\n#endif\n\nGHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept\n{\n    auto fs = status(p, ec);\n    if (ec) {\n        return false;\n    }\n    if (is_directory(fs)) {\n        directory_iterator iter(p, ec);\n        if (ec) {\n            return false;\n        }\n        return iter == directory_iterator();\n    }\n    else {\n        auto sz = file_size(p, ec);\n        if (ec) {\n            return false;\n        }\n        return sz == 0;\n    }\n}\n\nGHC_INLINE bool is_fifo(file_status s) noexcept\n{\n    return s.type() == file_type::fifo;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_fifo(const path& p)\n{\n    return is_fifo(status(p));\n}\n#endif\n\nGHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept\n{\n    return is_fifo(status(p, ec));\n}\n\nGHC_INLINE bool is_other(file_status s) noexcept\n{\n    return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_other(const path& p)\n{\n    return is_other(status(p));\n}\n#endif\n\nGHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept\n{\n    return is_other(status(p, ec));\n}\n\nGHC_INLINE bool is_regular_file(file_status s) noexcept\n{\n    return s.type() == file_type::regular;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_regular_file(const path& p)\n{\n    return is_regular_file(status(p));\n}\n#endif\n\nGHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept\n{\n    return is_regular_file(status(p, ec));\n}\n\nGHC_INLINE bool is_socket(file_status s) noexcept\n{\n    return s.type() == file_type::socket;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_socket(const path& p)\n{\n    return is_socket(status(p));\n}\n#endif\n\nGHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept\n{\n    return is_socket(status(p, ec));\n}\n\nGHC_INLINE bool is_symlink(file_status s) noexcept\n{\n    return s.type() == file_type::symlink;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool is_symlink(const path& p)\n{\n    return is_symlink(symlink_status(p));\n}\n#endif\n\nGHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept\n{\n    return is_symlink(symlink_status(p, ec));\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_time_type last_write_time(const path& p)\n{\n    std::error_code ec;\n    auto result = last_write_time(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept\n{\n    time_t result = 0;\n    ec.clear();\n    file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result);\n    return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void last_write_time(const path& p, file_time_type new_time)\n{\n    std::error_code ec;\n    last_write_time(p, new_time, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n}\n#endif\n\nGHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept\n{\n    ec.clear();\n    auto d = new_time.time_since_epoch();\n#ifdef GHC_OS_WINDOWS\n    std::shared_ptr<void> file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle);\n    FILETIME ft;\n    auto tt = std::chrono::duration_cast<std::chrono::microseconds>(d).count() * 10 + 116444736000000000;\n    ft.dwLowDateTime = static_cast<DWORD>(tt);\n    ft.dwHighDateTime = static_cast<DWORD>(tt >> 32);\n    if (!::SetFileTime(file.get(), 0, 0, &ft)) {\n        ec = detail::make_system_error();\n    }\n#elif defined(GHC_OS_MACOS)\n#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED\n#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300\n    struct ::stat fs;\n    if (::stat(p.c_str(), &fs) == 0) {\n        struct ::timeval tv[2];\n        tv[0].tv_sec = fs.st_atimespec.tv_sec;\n        tv[0].tv_usec = static_cast<int>(fs.st_atimespec.tv_nsec / 1000);\n        tv[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();\n        tv[1].tv_usec = static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>(d).count() % 1000000);\n        if (::utimes(p.c_str(), tv) == 0) {\n            return;\n        }\n    }\n    ec = detail::make_system_error();\n    return;\n#else\n    struct ::timespec times[2];\n    times[0].tv_sec = 0;\n    times[0].tv_nsec = UTIME_OMIT;\n    times[1].tv_sec = std::chrono::duration_cast<std::chrono::seconds>(d).count();\n    times[1].tv_nsec = 0;  // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000;\n    if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {\n        ec = detail::make_system_error();\n    }\n    return;\n#endif\n#endif\n#else\n#ifndef UTIME_OMIT\n#define UTIME_OMIT ((1l << 30) - 2l)\n#endif\n    struct ::timespec times[2];\n    times[0].tv_sec = 0;\n    times[0].tv_nsec = UTIME_OMIT;\n    times[1].tv_sec = static_cast<decltype(times[1].tv_sec)>(std::chrono::duration_cast<std::chrono::seconds>(d).count());\n    times[1].tv_nsec = static_cast<decltype(times[1].tv_nsec)>(std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() % 1000000000);\n#if defined(__ANDROID_API__) && __ANDROID_API__ < 12\n    if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {\n#else\n    if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {\n#endif\n        ec = detail::make_system_error();\n    }\n    return;\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void permissions(const path& p, perms prms, perm_options opts)\n{\n    std::error_code ec;\n    permissions(p, prms, opts, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n}\n#endif\n\nGHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept\n{\n    permissions(p, prms, perm_options::replace, ec);\n}\n\nGHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept\n{\n    if (static_cast<int>(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) {\n        ec = detail::make_error_code(detail::portable_error::invalid_argument);\n        return;\n    }\n    auto fs = symlink_status(p, ec);\n    if ((opts & perm_options::replace) != perm_options::replace) {\n        if ((opts & perm_options::add) == perm_options::add) {\n            prms = fs.permissions() | prms;\n        }\n        else {\n            prms = fs.permissions() & ~prms;\n        }\n    }\n#ifdef GHC_OS_WINDOWS\n#ifdef __GNUC__\n    auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p));\n    if (oldAttr != INVALID_FILE_ATTRIBUTES) {\n        DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY;\n        if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) {\n            return;\n        }\n    }\n    ec = detail::make_system_error();\n#else\n    int mode = 0;\n    if ((prms & perms::owner_read) == perms::owner_read) {\n        mode |= _S_IREAD;\n    }\n    if ((prms & perms::owner_write) == perms::owner_write) {\n        mode |= _S_IWRITE;\n    }\n    if (::_wchmod(p.wstring().c_str(), mode) != 0) {\n        ec = detail::make_system_error();\n    }\n#endif\n#else\n    if ((opts & perm_options::nofollow) != perm_options::nofollow) {\n        if (::chmod(p.c_str(), static_cast<mode_t>(prms)) != 0) {\n            ec = detail::make_system_error();\n        }\n    }\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path proximate(const path& p, std::error_code& ec)\n{\n    auto cp = current_path(ec);\n    if (!ec) {\n        return proximate(p, cp, ec);\n    }\n    return path();\n}\n#endif\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path proximate(const path& p, const path& base)\n{\n    return weakly_canonical(p).lexically_proximate(weakly_canonical(base));\n}\n#endif\n\nGHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec)\n{\n    return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec));\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path read_symlink(const path& p)\n{\n    std::error_code ec;\n    auto result = read_symlink(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path read_symlink(const path& p, std::error_code& ec)\n{\n    file_status fs = symlink_status(p, ec);\n    if (fs.type() != file_type::symlink) {\n        ec = detail::make_error_code(detail::portable_error::invalid_argument);\n        return path();\n    }\n    auto result = detail::resolveSymlink(p, ec);\n    return ec ? path() : result;\n}\n\nGHC_INLINE path relative(const path& p, std::error_code& ec)\n{\n    return relative(p, current_path(ec), ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path relative(const path& p, const path& base)\n{\n    return weakly_canonical(p).lexically_relative(weakly_canonical(base));\n}\n#endif\n\nGHC_INLINE path relative(const path& p, const path& base, std::error_code& ec)\n{\n    return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec));\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool remove(const path& p)\n{\n    std::error_code ec;\n    auto result = remove(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n#ifdef GHC_USE_WCHAR_T\n    auto cstr = p.c_str();\n#else\n    std::wstring np = detail::fromUtf8<std::wstring>(p.u8string());\n    auto cstr = np.c_str();\n#endif\n    DWORD attr = GetFileAttributesW(cstr);\n    if (attr == INVALID_FILE_ATTRIBUTES) {\n        auto error = ::GetLastError();\n        if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) {\n            return false;\n        }\n        ec = detail::make_system_error(error);\n    }\n    if (!ec) {\n        if (attr & FILE_ATTRIBUTE_DIRECTORY) {\n            if (!RemoveDirectoryW(cstr)) {\n                ec = detail::make_system_error();\n            }\n        }\n        else {\n            if (!DeleteFileW(cstr)) {\n                ec = detail::make_system_error();\n            }\n        }\n    }\n#else\n    if (::remove(p.c_str()) == -1) {\n        auto error = errno;\n        if (error == ENOENT) {\n            return false;\n        }\n        ec = detail::make_system_error();\n    }\n#endif\n    return ec ? false : true;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE uintmax_t remove_all(const path& p)\n{\n    std::error_code ec;\n    auto result = remove_all(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n    uintmax_t count = 0;\n    if (p == \"/\") {\n        ec = detail::make_error_code(detail::portable_error::not_supported);\n        return static_cast<uintmax_t>(-1);\n    }\n    std::error_code tec;\n    auto fs = status(p, tec);\n    if (exists(fs) && is_directory(fs)) {\n        for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) {\n            if (ec && !detail::is_not_found_error(ec)) {\n                break;\n            }\n            bool is_symlink_result = iter->is_symlink(ec);\n            if (ec)\n                return static_cast<uintmax_t>(-1);\n            if (!is_symlink_result && iter->is_directory(ec)) {\n                count += remove_all(iter->path(), ec);\n                if (ec) {\n                    return static_cast<uintmax_t>(-1);\n                }\n            }\n            else {\n                if (!ec) {\n                    remove(iter->path(), ec);\n                }\n                if (ec) {\n                    return static_cast<uintmax_t>(-1);\n                }\n                ++count;\n            }\n        }\n    }\n    if (!ec) {\n        if (remove(p, ec)) {\n            ++count;\n        }\n    }\n    if (ec) {\n        return static_cast<uintmax_t>(-1);\n    }\n    return count;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void rename(const path& from, const path& to)\n{\n    std::error_code ec;\n    rename(from, to, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec);\n    }\n}\n#endif\n\nGHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    if (from != to) {\n        if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) {\n            ec = detail::make_system_error();\n        }\n    }\n#else\n    if (from != to) {\n        if (::rename(from.c_str(), to.c_str()) != 0) {\n            ec = detail::make_system_error();\n        }\n    }\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void resize_file(const path& p, uintmax_t size)\n{\n    std::error_code ec;\n    resize_file(p, size, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n}\n#endif\n\nGHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    LARGE_INTEGER lisize;\n    lisize.QuadPart = static_cast<LONGLONG>(size);\n    if (lisize.QuadPart < 0) {\n#ifdef ERROR_FILE_TOO_LARGE\n        ec = detail::make_system_error(ERROR_FILE_TOO_LARGE);\n#else\n        ec = detail::make_system_error(223);\n#endif\n        return;\n    }\n    std::shared_ptr<void> file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle);\n    if (file.get() == INVALID_HANDLE_VALUE) {\n        ec = detail::make_system_error();\n    }\n    else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) {\n        ec = detail::make_system_error();\n    }\n#else\n    if (::truncate(p.c_str(), static_cast<off_t>(size)) != 0) {\n        ec = detail::make_system_error();\n    }\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE space_info space(const path& p)\n{\n    std::error_code ec;\n    auto result = space(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }};\n    ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }};\n    ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }};\n    if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) {\n        ec = detail::make_system_error();\n        return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};\n    }\n    return {static_cast<uintmax_t>(totalNumberOfBytes.QuadPart), static_cast<uintmax_t>(totalNumberOfFreeBytes.QuadPart), static_cast<uintmax_t>(freeBytesAvailableToCaller.QuadPart)};\n#else\n    struct ::statvfs sfs;\n    if (::statvfs(p.c_str(), &sfs) != 0) {\n        ec = detail::make_system_error();\n        return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1)};\n    }\n    return {static_cast<uintmax_t>(sfs.f_blocks * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bfree * sfs.f_frsize), static_cast<uintmax_t>(sfs.f_bavail * sfs.f_frsize)};\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_status status(const path& p)\n{\n    std::error_code ec;\n    auto result = status(p, ec);\n    if (result.type() == file_type::none) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept\n{\n    return detail::status_ex(p, ec);\n}\n\nGHC_INLINE bool status_known(file_status s) noexcept\n{\n    return s.type() != file_type::none;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_status symlink_status(const path& p)\n{\n    std::error_code ec;\n    auto result = symlink_status(p, ec);\n    if (result.type() == file_type::none) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept\n{\n    return detail::symlink_status_ex(p, ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path temp_directory_path()\n{\n    std::error_code ec;\n    path result = temp_directory_path(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path temp_directory_path(std::error_code& ec) noexcept\n{\n    ec.clear();\n#ifdef GHC_OS_WINDOWS\n    wchar_t buffer[512];\n    auto rc = GetTempPathW(511, buffer);\n    if (!rc || rc > 511) {\n        ec = detail::make_system_error();\n        return path();\n    }\n    return path(std::wstring(buffer));\n#else\n    static const char* temp_vars[] = {\"TMPDIR\", \"TMP\", \"TEMP\", \"TEMPDIR\", nullptr};\n    const char* temp_path = nullptr;\n    for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) {\n        temp_path = std::getenv(*temp_name);\n        if (temp_path) {\n            return path(temp_path);\n        }\n    }\n    return path(\"/tmp\");\n#endif\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE path weakly_canonical(const path& p)\n{\n    std::error_code ec;\n    auto result = weakly_canonical(p, ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);\n    }\n    return result;\n}\n#endif\n\nGHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept\n{\n    path result;\n    ec.clear();\n    bool scan = true;\n    for (auto pe : p) {\n        if (scan) {\n            std::error_code tec;\n            if (exists(result / pe, tec)) {\n                result /= pe;\n            }\n            else {\n                if (ec) {\n                    return path();\n                }\n                scan = false;\n                if (!result.empty()) {\n                    result = canonical(result, ec) / pe;\n                    if (ec) {\n                        break;\n                    }\n                }\n                else {\n                    result /= pe;\n                }\n            }\n        }\n        else {\n            result /= pe;\n        }\n    }\n    if (scan) {\n        if (!result.empty()) {\n            result = canonical(result, ec);\n        }\n    }\n    return ec ? path() : result.lexically_normal();\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.11 class file_status\n// 30.10.11.1 constructors and destructor\nGHC_INLINE file_status::file_status() noexcept\n    : file_status(file_type::none)\n{\n}\n\nGHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept\n    : _type(ft)\n    , _perms(prms)\n{\n}\n\nGHC_INLINE file_status::file_status(const file_status& other) noexcept\n    : _type(other._type)\n    , _perms(other._perms)\n{\n}\n\nGHC_INLINE file_status::file_status(file_status&& other) noexcept\n    : _type(other._type)\n    , _perms(other._perms)\n{\n}\n\nGHC_INLINE file_status::~file_status() {}\n\n// assignments:\nGHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept\n{\n    _type = rhs._type;\n    _perms = rhs._perms;\n    return *this;\n}\n\nGHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept\n{\n    _type = rhs._type;\n    _perms = rhs._perms;\n    return *this;\n}\n\n// 30.10.11.3 modifiers\nGHC_INLINE void file_status::type(file_type ft) noexcept\n{\n    _type = ft;\n}\n\nGHC_INLINE void file_status::permissions(perms prms) noexcept\n{\n    _perms = prms;\n}\n\n// 30.10.11.2 observers\nGHC_INLINE file_type file_status::type() const noexcept\n{\n    return _type;\n}\n\nGHC_INLINE perms file_status::permissions() const noexcept\n{\n    return _perms;\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.12 class directory_entry\n// 30.10.12.1 constructors and destructor\n// directory_entry::directory_entry() noexcept = default;\n// directory_entry::directory_entry(const directory_entry&) = default;\n// directory_entry::directory_entry(directory_entry&&) noexcept = default;\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE directory_entry::directory_entry(const filesystem::path& p)\n    : _path(p)\n    , _file_size(static_cast<uintmax_t>(-1))\n#ifndef GHC_OS_WINDOWS\n    , _hard_link_count(static_cast<uintmax_t>(-1))\n#endif\n    , _last_write_time(0)\n{\n    refresh();\n}\n#endif\n\nGHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec)\n    : _path(p)\n    , _file_size(static_cast<uintmax_t>(-1))\n#ifndef GHC_OS_WINDOWS\n    , _hard_link_count(static_cast<uintmax_t>(-1))\n#endif\n    , _last_write_time(0)\n{\n    refresh(ec);\n}\n\nGHC_INLINE directory_entry::~directory_entry() {}\n\n// assignments:\n// directory_entry& directory_entry::operator=(const directory_entry&) = default;\n// directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default;\n\n// 30.10.12.2 directory_entry modifiers\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void directory_entry::assign(const filesystem::path& p)\n{\n    _path = p;\n    refresh();\n}\n#endif\n\nGHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec)\n{\n    _path = p;\n    refresh(ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void directory_entry::replace_filename(const filesystem::path& p)\n{\n    _path.replace_filename(p);\n    refresh();\n}\n#endif\n\nGHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec)\n{\n    _path.replace_filename(p);\n    refresh(ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void directory_entry::refresh()\n{\n    std::error_code ec;\n    refresh(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);\n    }\n}\n#endif\n\nGHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept\n{\n#ifdef GHC_OS_WINDOWS\n    _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time);\n#else\n    _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time);\n#endif\n}\n\n// 30.10.12.3 directory_entry observers\nGHC_INLINE const filesystem::path& directory_entry::path() const noexcept\n{\n    return _path;\n}\n\nGHC_INLINE directory_entry::operator const filesystem::path&() const noexcept\n{\n    return _path;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_type directory_entry::status_file_type() const\n{\n    return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type();\n}\n#endif\n\nGHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept\n{\n    if(_status.type() != file_type::none) {\n        ec.clear();\n        return _status.type();\n    }\n    return filesystem::status(path(), ec).type();\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::exists() const\n{\n    return status_file_type() != file_type::not_found;\n}\n#endif\n\nGHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) != file_type::not_found;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_block_file() const\n{\n    return status_file_type() == file_type::block;\n}\n#endif\nGHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::block;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_character_file() const\n{\n    return status_file_type() == file_type::character;\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::character;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_directory() const\n{\n    return status_file_type() == file_type::directory;\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::directory;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_fifo() const\n{\n    return status_file_type() == file_type::fifo;\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::fifo;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_other() const\n{\n    auto ft = status_file_type();\n    return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink();\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept\n{\n    auto ft = status_file_type(ec);\n    bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec);\n    return !ec && other;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_regular_file() const\n{\n    return status_file_type() == file_type::regular;\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::regular;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_socket() const\n{\n    return status_file_type() == file_type::socket;\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept\n{\n    return status_file_type(ec) == file_type::socket;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE bool directory_entry::is_symlink() const\n{\n    return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status());\n}\n#endif\n\nGHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept\n{\n    if(_symlink_status.type() != file_type::none) {\n        ec.clear();\n        return _symlink_status.type() == file_type::symlink;\n    }\n    return filesystem::is_symlink(symlink_status(ec));\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE uintmax_t directory_entry::file_size() const\n{\n    if (_file_size != static_cast<uintmax_t>(-1)) {\n        return _file_size;\n    }\n    return filesystem::file_size(path());\n}\n#endif\n\nGHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept\n{\n    if (_file_size != static_cast<uintmax_t>(-1)) {\n        ec.clear();\n        return _file_size;\n    }\n    return filesystem::file_size(path(), ec);\n}\n\n#ifndef GHC_OS_WEB\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE uintmax_t directory_entry::hard_link_count() const\n{\n#ifndef GHC_OS_WINDOWS\n    if (_hard_link_count != static_cast<uintmax_t>(-1)) {\n        return _hard_link_count;\n    }\n#endif\n    return filesystem::hard_link_count(path());\n}\n#endif\n\nGHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept\n{\n#ifndef GHC_OS_WINDOWS\n    if (_hard_link_count != static_cast<uintmax_t>(-1)) {\n        ec.clear();\n        return _hard_link_count;\n    }\n#endif\n    return filesystem::hard_link_count(path(), ec);\n}\n#endif\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_time_type directory_entry::last_write_time() const\n{\n    if (_last_write_time != 0) {\n        return std::chrono::system_clock::from_time_t(_last_write_time);\n    }\n    return filesystem::last_write_time(path());\n}\n#endif\n\nGHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept\n{\n    if (_last_write_time != 0) {\n        ec.clear();\n        return std::chrono::system_clock::from_time_t(_last_write_time);\n    }\n    return filesystem::last_write_time(path(), ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_status directory_entry::status() const\n{\n    if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {\n        return _status;\n    }\n    return filesystem::status(path());\n}\n#endif\n\nGHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept\n{\n    if (_status.type() != file_type::none && _status.permissions() != perms::unknown) {\n        ec.clear();\n        return _status;\n    }\n    return filesystem::status(path(), ec);\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE file_status directory_entry::symlink_status() const\n{\n    if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {\n        return _symlink_status;\n    }\n    return filesystem::symlink_status(path());\n}\n#endif\n\nGHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept\n{\n    if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) {\n        ec.clear();\n        return _symlink_status;\n    }\n    return filesystem::symlink_status(path(), ec);\n}\n\n#ifdef GHC_HAS_THREEWAY_COMP\nGHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept\n{\n    return _path <=> rhs._path;\n}\n#endif\n\nGHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept\n{\n    return _path < rhs._path;\n}\n\nGHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept\n{\n    return _path == rhs._path;\n}\n\nGHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept\n{\n    return _path != rhs._path;\n}\n\nGHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept\n{\n    return _path <= rhs._path;\n}\n\nGHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept\n{\n    return _path > rhs._path;\n}\n\nGHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept\n{\n    return _path >= rhs._path;\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.13 class directory_iterator\n\n#ifdef GHC_OS_WINDOWS\nclass directory_iterator::impl\n{\npublic:\n    impl(const path& p, directory_options options)\n        : _base(p)\n        , _options(options)\n        , _dirHandle(INVALID_HANDLE_VALUE)\n    {\n        if (!_base.empty()) {\n            ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW));\n            if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / \"*\")), &_findData)) != INVALID_HANDLE_VALUE) {\n                if (std::wstring(_findData.cFileName) == L\".\" || std::wstring(_findData.cFileName) == L\"..\") {\n                    increment(_ec);\n                }\n                else {\n                    _dir_entry._path = _base / std::wstring(_findData.cFileName);\n                    copyToDirEntry(_ec);\n                }\n            }\n            else {\n                auto error = ::GetLastError();\n                _base = filesystem::path();\n                if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) {\n                    _ec = detail::make_system_error();\n                }\n            }\n        }\n    }\n    impl(const impl& other) = delete;\n    ~impl()\n    {\n        if (_dirHandle != INVALID_HANDLE_VALUE) {\n            FindClose(_dirHandle);\n            _dirHandle = INVALID_HANDLE_VALUE;\n        }\n    }\n    void increment(std::error_code& ec)\n    {\n        if (_dirHandle != INVALID_HANDLE_VALUE) {\n            do {\n                if (FindNextFileW(_dirHandle, &_findData)) {\n                    _dir_entry._path = _base;\n#ifdef GHC_USE_WCHAR_T\n                    _dir_entry._path.append_name(_findData.cFileName);\n#else\n#ifdef GHC_RAISE_UNICODE_ERRORS\n                    try {\n                        _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());\n                    }\n                    catch (filesystem_error& fe) {\n                        ec = fe.code();\n                        return;\n                    }\n#else\n                    _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str());\n#endif\n#endif\n                    copyToDirEntry(ec);\n                }\n                else {\n                    auto err = ::GetLastError();\n                    if (err != ERROR_NO_MORE_FILES) {\n                        _ec = ec = detail::make_system_error(err);\n                    }\n                    FindClose(_dirHandle);\n                    _dirHandle = INVALID_HANDLE_VALUE;\n                    _dir_entry._path.clear();\n                    break;\n                }\n            } while (std::wstring(_findData.cFileName) == L\".\" || std::wstring(_findData.cFileName) == L\"..\");\n        }\n        else {\n            ec = _ec;\n        }\n    }\n    void copyToDirEntry(std::error_code& ec)\n    {\n        if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {\n            _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time);\n        }\n        else {\n            _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time);\n            _dir_entry._symlink_status = _dir_entry._status;\n        }\n        if (ec) {\n            if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) {\n                ec.clear();\n            }\n            else {\n                _dir_entry._file_size = static_cast<uintmax_t>(-1);\n                _dir_entry._last_write_time = 0;\n            }\n        }\n    }\n    path _base;\n    directory_options _options;\n    WIN32_FIND_DATAW _findData;\n    HANDLE _dirHandle;\n    directory_entry _dir_entry;\n    std::error_code _ec;\n};\n#else\n// POSIX implementation\nclass directory_iterator::impl\n{\npublic:\n    impl(const path& path, directory_options options)\n        : _base(path)\n        , _options(options)\n        , _dir(nullptr)\n        , _entry(nullptr)\n    {\n        if (!path.empty()) {\n            _dir = ::opendir(path.native().c_str());\n            if (!_dir) {\n                auto error = errno;\n                _base = filesystem::path();\n                if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) {\n                    _ec = detail::make_system_error();\n                }\n            }\n            else {\n                increment(_ec);\n            }\n        }\n    }\n    impl(const impl& other) = delete;\n    ~impl()\n    {\n        if (_dir) {\n            ::closedir(_dir);\n        }\n    }\n    void increment(std::error_code& ec)\n    {\n        if (_dir) {\n            bool skip;\n            do {\n                skip = false;\n                errno = 0;\n                _entry = ::readdir(_dir);\n                if (_entry) {\n                    _dir_entry._path = _base;\n                    _dir_entry._path.append_name(_entry->d_name);\n                    copyToDirEntry();\n                    if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) {\n                        ec.clear();\n                        skip = true;\n                    }\n                }\n                else {\n                    ::closedir(_dir);\n                    _dir = nullptr;\n                    _dir_entry._path.clear();\n                    if (errno) {\n                        ec = detail::make_system_error();\n                    }\n                    break;\n                }\n            } while (skip || std::strcmp(_entry->d_name, \".\") == 0 || std::strcmp(_entry->d_name, \"..\") == 0);\n        }\n    }\n    void copyToDirEntry()\n    {\n        _dir_entry._symlink_status.permissions(perms::unknown);\n        switch(_entry->d_type) {\n            case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break;\n            case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break;\n            case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break;\n            case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break;\n            case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break;\n            case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break;\n            case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break;\n            default: _dir_entry._symlink_status.type(file_type::unknown); break;\n        }\n        if (_entry->d_type != DT_LNK) {\n            _dir_entry._status = _dir_entry._symlink_status;\n        }\n        else {\n            _dir_entry._status.type(file_type::none);\n            _dir_entry._status.permissions(perms::unknown);\n        }\n        _dir_entry._file_size = static_cast<uintmax_t>(-1);\n        _dir_entry._hard_link_count = static_cast<uintmax_t>(-1);\n        _dir_entry._last_write_time = 0;\n    }\n    path _base;\n    directory_options _options;\n    DIR* _dir;\n    struct ::dirent* _entry;\n    directory_entry _dir_entry;\n    std::error_code _ec;\n};\n#endif\n\n// 30.10.13.1 member functions\nGHC_INLINE directory_iterator::directory_iterator() noexcept\n    : _impl(new impl(path(), directory_options::none))\n{\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE directory_iterator::directory_iterator(const path& p)\n    : _impl(new impl(p, directory_options::none))\n{\n    if (_impl->_ec) {\n        throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);\n    }\n    _impl->_ec.clear();\n}\n\nGHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options)\n    : _impl(new impl(p, options))\n{\n    if (_impl->_ec) {\n        throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec);\n    }\n}\n#endif\n\nGHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept\n    : _impl(new impl(p, directory_options::none))\n{\n    if (_impl->_ec) {\n        ec = _impl->_ec;\n    }\n}\n\nGHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept\n    : _impl(new impl(p, options))\n{\n    if (_impl->_ec) {\n        ec = _impl->_ec;\n    }\n}\n\nGHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs)\n    : _impl(rhs._impl)\n{\n}\n\nGHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept\n    : _impl(std::move(rhs._impl))\n{\n}\n\nGHC_INLINE directory_iterator::~directory_iterator() {}\n\nGHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs)\n{\n    _impl = rhs._impl;\n    return *this;\n}\n\nGHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept\n{\n    _impl = std::move(rhs._impl);\n    return *this;\n}\n\nGHC_INLINE const directory_entry& directory_iterator::operator*() const\n{\n    return _impl->_dir_entry;\n}\n\nGHC_INLINE const directory_entry* directory_iterator::operator->() const\n{\n    return &_impl->_dir_entry;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE directory_iterator& directory_iterator::operator++()\n{\n    std::error_code ec;\n    _impl->increment(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec);\n    }\n    return *this;\n}\n#endif\n\nGHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept\n{\n    _impl->increment(ec);\n    return *this;\n}\n\nGHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const\n{\n    return _impl->_dir_entry._path == rhs._impl->_dir_entry._path;\n}\n\nGHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const\n{\n    return _impl->_dir_entry._path != rhs._impl->_dir_entry._path;\n}\n\n// 30.10.13.2 directory_iterator non-member functions\n\nGHC_INLINE directory_iterator begin(directory_iterator iter) noexcept\n{\n    return iter;\n}\n\nGHC_INLINE directory_iterator end(const directory_iterator&) noexcept\n{\n    return directory_iterator();\n}\n\n//-----------------------------------------------------------------------------\n// 30.10.14 class recursive_directory_iterator\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept\n    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))\n{\n    _impl->_dir_iter_stack.push(directory_iterator());\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p)\n    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))\n{\n    _impl->_dir_iter_stack.push(directory_iterator(p));\n}\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options)\n    : _impl(new recursive_directory_iterator_impl(options, true))\n{\n    _impl->_dir_iter_stack.push(directory_iterator(p, options));\n}\n#endif\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept\n    : _impl(new recursive_directory_iterator_impl(options, true))\n{\n    _impl->_dir_iter_stack.push(directory_iterator(p, options, ec));\n}\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept\n    : _impl(new recursive_directory_iterator_impl(directory_options::none, true))\n{\n    _impl->_dir_iter_stack.push(directory_iterator(p, ec));\n}\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs)\n    : _impl(rhs._impl)\n{\n}\n\nGHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept\n    : _impl(std::move(rhs._impl))\n{\n}\n\nGHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {}\n\n// 30.10.14.1 observers\nGHC_INLINE directory_options recursive_directory_iterator::options() const\n{\n    return _impl->_options;\n}\n\nGHC_INLINE int recursive_directory_iterator::depth() const\n{\n    return static_cast<int>(_impl->_dir_iter_stack.size() - 1);\n}\n\nGHC_INLINE bool recursive_directory_iterator::recursion_pending() const\n{\n    return _impl->_recursion_pending;\n}\n\nGHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const\n{\n    return *(_impl->_dir_iter_stack.top());\n}\n\nGHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const\n{\n    return &(*(_impl->_dir_iter_stack.top()));\n}\n\n// 30.10.14.1 modifiers recursive_directory_iterator&\nGHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs)\n{\n    _impl = rhs._impl;\n    return *this;\n}\n\nGHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept\n{\n    _impl = std::move(rhs._impl);\n    return *this;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++()\n{\n    std::error_code ec;\n    increment(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);\n    }\n    return *this;\n}\n#endif\n\nGHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept\n{\n    bool isDir = (*this)->is_directory(ec);\n    bool isSymLink = !ec && (*this)->is_symlink(ec);\n    if(!ec) {\n        if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) {\n            _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec));\n        }\n        else {\n            _impl->_dir_iter_stack.top().increment(ec);\n        }\n        if (!ec) {\n            while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) {\n                _impl->_dir_iter_stack.pop();\n                _impl->_dir_iter_stack.top().increment(ec);\n            }\n        }\n        else if (!_impl->_dir_iter_stack.empty()) {\n            _impl->_dir_iter_stack.pop();\n        }\n        _impl->_recursion_pending = true;\n    }\n    return *this;\n}\n\n#ifdef GHC_WITH_EXCEPTIONS\nGHC_INLINE void recursive_directory_iterator::pop()\n{\n    std::error_code ec;\n    pop(ec);\n    if (ec) {\n        throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec);\n    }\n}\n#endif\n\nGHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec)\n{\n    if (depth() == 0) {\n        *this = recursive_directory_iterator();\n    }\n    else {\n        do {\n            _impl->_dir_iter_stack.pop();\n            _impl->_dir_iter_stack.top().increment(ec);\n        } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator());\n    }\n}\n\nGHC_INLINE void recursive_directory_iterator::disable_recursion_pending()\n{\n    _impl->_recursion_pending = false;\n}\n\n// other members as required by 27.2.3, input iterators\nGHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const\n{\n    return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top();\n}\n\nGHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const\n{\n    return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top();\n}\n\n// 30.10.14.2 directory_iterator non-member functions\nGHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept\n{\n    return iter;\n}\n\nGHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept\n{\n    return recursive_directory_iterator();\n}\n\n#endif  // GHC_EXPAND_IMPL\n\n}  // namespace filesystem\n}  // namespace ghc\n\n// cleanup some macros\n#undef GHC_INLINE\n#undef GHC_EXPAND_IMPL\n\n#endif  // GHC_FILESYSTEM_H\n"
  },
  {
    "path": "include/glad/glad.h",
    "content": "/*\n\n    OpenGL, OpenGL ES loader generated by glad 0.1.33 on Thu Apr  9 12:37:38 2020.\n\n    Language/Generator: C/C++\n    Specification: gl\n    APIs: gl=4.6, gles2=3.2\n    Profile: compatibility\n    Extensions:\n        GL_ARB_clip_control,\n        GL_EXT_clip_control\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --profile=\"compatibility\" --api=\"gl=4.6,gles2=3.2\" --generator=\"c\" --spec=\"gl\" --extensions=\"GL_ARB_clip_control,GL_EXT_clip_control\"\n    Online:\n        https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_clip_control&extensions=GL_EXT_clip_control\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#ifdef __gl2_h_\n#error OpenGL ES 2 header already included, remove this include, glad already provides it\n#endif\n#define __gl2_h_\n\n#ifdef __gl3_h_\n#error OpenGL ES 3 header already included, remove this include, glad already provides it\n#endif\n#define __gl3_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\nGLAPI int gladLoadGLES2Loader(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_QUADS 0x0007\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_STACK_OVERFLOW 0x0503\n#define GL_STACK_UNDERFLOW 0x0504\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_CURRENT_BIT 0x00000001\n#define GL_POINT_BIT 0x00000002\n#define GL_LINE_BIT 0x00000004\n#define GL_POLYGON_BIT 0x00000008\n#define GL_POLYGON_STIPPLE_BIT 0x00000010\n#define GL_PIXEL_MODE_BIT 0x00000020\n#define GL_LIGHTING_BIT 0x00000040\n#define GL_FOG_BIT 0x00000080\n#define GL_ACCUM_BUFFER_BIT 0x00000200\n#define GL_VIEWPORT_BIT 0x00000800\n#define GL_TRANSFORM_BIT 0x00001000\n#define GL_ENABLE_BIT 0x00002000\n#define GL_HINT_BIT 0x00008000\n#define GL_EVAL_BIT 0x00010000\n#define GL_LIST_BIT 0x00020000\n#define GL_TEXTURE_BIT 0x00040000\n#define GL_SCISSOR_BIT 0x00080000\n#define GL_ALL_ATTRIB_BITS 0xFFFFFFFF\n#define GL_QUAD_STRIP 0x0008\n#define GL_POLYGON 0x0009\n#define GL_ACCUM 0x0100\n#define GL_LOAD 0x0101\n#define GL_RETURN 0x0102\n#define GL_MULT 0x0103\n#define GL_ADD 0x0104\n#define GL_AUX0 0x0409\n#define GL_AUX1 0x040A\n#define GL_AUX2 0x040B\n#define GL_AUX3 0x040C\n#define GL_2D 0x0600\n#define GL_3D 0x0601\n#define GL_3D_COLOR 0x0602\n#define GL_3D_COLOR_TEXTURE 0x0603\n#define GL_4D_COLOR_TEXTURE 0x0604\n#define GL_PASS_THROUGH_TOKEN 0x0700\n#define GL_POINT_TOKEN 0x0701\n#define GL_LINE_TOKEN 0x0702\n#define GL_POLYGON_TOKEN 0x0703\n#define GL_BITMAP_TOKEN 0x0704\n#define GL_DRAW_PIXEL_TOKEN 0x0705\n#define GL_COPY_PIXEL_TOKEN 0x0706\n#define GL_LINE_RESET_TOKEN 0x0707\n#define GL_EXP 0x0800\n#define GL_EXP2 0x0801\n#define GL_COEFF 0x0A00\n#define GL_ORDER 0x0A01\n#define GL_DOMAIN 0x0A02\n#define GL_PIXEL_MAP_I_TO_I 0x0C70\n#define GL_PIXEL_MAP_S_TO_S 0x0C71\n#define GL_PIXEL_MAP_I_TO_R 0x0C72\n#define GL_PIXEL_MAP_I_TO_G 0x0C73\n#define GL_PIXEL_MAP_I_TO_B 0x0C74\n#define GL_PIXEL_MAP_I_TO_A 0x0C75\n#define GL_PIXEL_MAP_R_TO_R 0x0C76\n#define GL_PIXEL_MAP_G_TO_G 0x0C77\n#define GL_PIXEL_MAP_B_TO_B 0x0C78\n#define GL_PIXEL_MAP_A_TO_A 0x0C79\n#define GL_CURRENT_COLOR 0x0B00\n#define GL_CURRENT_INDEX 0x0B01\n#define GL_CURRENT_NORMAL 0x0B02\n#define GL_CURRENT_TEXTURE_COORDS 0x0B03\n#define GL_CURRENT_RASTER_COLOR 0x0B04\n#define GL_CURRENT_RASTER_INDEX 0x0B05\n#define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06\n#define GL_CURRENT_RASTER_POSITION 0x0B07\n#define GL_CURRENT_RASTER_POSITION_VALID 0x0B08\n#define GL_CURRENT_RASTER_DISTANCE 0x0B09\n#define GL_POINT_SMOOTH 0x0B10\n#define GL_LINE_STIPPLE 0x0B24\n#define GL_LINE_STIPPLE_PATTERN 0x0B25\n#define GL_LINE_STIPPLE_REPEAT 0x0B26\n#define GL_LIST_MODE 0x0B30\n#define GL_MAX_LIST_NESTING 0x0B31\n#define GL_LIST_BASE 0x0B32\n#define GL_LIST_INDEX 0x0B33\n#define GL_POLYGON_STIPPLE 0x0B42\n#define GL_EDGE_FLAG 0x0B43\n#define GL_LIGHTING 0x0B50\n#define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51\n#define GL_LIGHT_MODEL_TWO_SIDE 0x0B52\n#define GL_LIGHT_MODEL_AMBIENT 0x0B53\n#define GL_SHADE_MODEL 0x0B54\n#define GL_COLOR_MATERIAL_FACE 0x0B55\n#define GL_COLOR_MATERIAL_PARAMETER 0x0B56\n#define GL_COLOR_MATERIAL 0x0B57\n#define GL_FOG 0x0B60\n#define GL_FOG_INDEX 0x0B61\n#define GL_FOG_DENSITY 0x0B62\n#define GL_FOG_START 0x0B63\n#define GL_FOG_END 0x0B64\n#define GL_FOG_MODE 0x0B65\n#define GL_FOG_COLOR 0x0B66\n#define GL_ACCUM_CLEAR_VALUE 0x0B80\n#define GL_MATRIX_MODE 0x0BA0\n#define GL_NORMALIZE 0x0BA1\n#define GL_MODELVIEW_STACK_DEPTH 0x0BA3\n#define GL_PROJECTION_STACK_DEPTH 0x0BA4\n#define GL_TEXTURE_STACK_DEPTH 0x0BA5\n#define GL_MODELVIEW_MATRIX 0x0BA6\n#define GL_PROJECTION_MATRIX 0x0BA7\n#define GL_TEXTURE_MATRIX 0x0BA8\n#define GL_ATTRIB_STACK_DEPTH 0x0BB0\n#define GL_ALPHA_TEST 0x0BC0\n#define GL_ALPHA_TEST_FUNC 0x0BC1\n#define GL_ALPHA_TEST_REF 0x0BC2\n#define GL_LOGIC_OP 0x0BF1\n#define GL_AUX_BUFFERS 0x0C00\n#define GL_INDEX_CLEAR_VALUE 0x0C20\n#define GL_INDEX_WRITEMASK 0x0C21\n#define GL_INDEX_MODE 0x0C30\n#define GL_RGBA_MODE 0x0C31\n#define GL_RENDER_MODE 0x0C40\n#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50\n#define GL_POINT_SMOOTH_HINT 0x0C51\n#define GL_FOG_HINT 0x0C54\n#define GL_TEXTURE_GEN_S 0x0C60\n#define GL_TEXTURE_GEN_T 0x0C61\n#define GL_TEXTURE_GEN_R 0x0C62\n#define GL_TEXTURE_GEN_Q 0x0C63\n#define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0\n#define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1\n#define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2\n#define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3\n#define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4\n#define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5\n#define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6\n#define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7\n#define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8\n#define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9\n#define GL_MAP_COLOR 0x0D10\n#define GL_MAP_STENCIL 0x0D11\n#define GL_INDEX_SHIFT 0x0D12\n#define GL_INDEX_OFFSET 0x0D13\n#define GL_RED_SCALE 0x0D14\n#define GL_RED_BIAS 0x0D15\n#define GL_ZOOM_X 0x0D16\n#define GL_ZOOM_Y 0x0D17\n#define GL_GREEN_SCALE 0x0D18\n#define GL_GREEN_BIAS 0x0D19\n#define GL_BLUE_SCALE 0x0D1A\n#define GL_BLUE_BIAS 0x0D1B\n#define GL_ALPHA_SCALE 0x0D1C\n#define GL_ALPHA_BIAS 0x0D1D\n#define GL_DEPTH_SCALE 0x0D1E\n#define GL_DEPTH_BIAS 0x0D1F\n#define GL_MAX_EVAL_ORDER 0x0D30\n#define GL_MAX_LIGHTS 0x0D31\n#define GL_MAX_CLIP_PLANES 0x0D32\n#define GL_MAX_PIXEL_MAP_TABLE 0x0D34\n#define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35\n#define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36\n#define GL_MAX_NAME_STACK_DEPTH 0x0D37\n#define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38\n#define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39\n#define GL_INDEX_BITS 0x0D51\n#define GL_RED_BITS 0x0D52\n#define GL_GREEN_BITS 0x0D53\n#define GL_BLUE_BITS 0x0D54\n#define GL_ALPHA_BITS 0x0D55\n#define GL_DEPTH_BITS 0x0D56\n#define GL_STENCIL_BITS 0x0D57\n#define GL_ACCUM_RED_BITS 0x0D58\n#define GL_ACCUM_GREEN_BITS 0x0D59\n#define GL_ACCUM_BLUE_BITS 0x0D5A\n#define GL_ACCUM_ALPHA_BITS 0x0D5B\n#define GL_NAME_STACK_DEPTH 0x0D70\n#define GL_AUTO_NORMAL 0x0D80\n#define GL_MAP1_COLOR_4 0x0D90\n#define GL_MAP1_INDEX 0x0D91\n#define GL_MAP1_NORMAL 0x0D92\n#define GL_MAP1_TEXTURE_COORD_1 0x0D93\n#define GL_MAP1_TEXTURE_COORD_2 0x0D94\n#define GL_MAP1_TEXTURE_COORD_3 0x0D95\n#define GL_MAP1_TEXTURE_COORD_4 0x0D96\n#define GL_MAP1_VERTEX_3 0x0D97\n#define GL_MAP1_VERTEX_4 0x0D98\n#define GL_MAP2_COLOR_4 0x0DB0\n#define GL_MAP2_INDEX 0x0DB1\n#define GL_MAP2_NORMAL 0x0DB2\n#define GL_MAP2_TEXTURE_COORD_1 0x0DB3\n#define GL_MAP2_TEXTURE_COORD_2 0x0DB4\n#define GL_MAP2_TEXTURE_COORD_3 0x0DB5\n#define GL_MAP2_TEXTURE_COORD_4 0x0DB6\n#define GL_MAP2_VERTEX_3 0x0DB7\n#define GL_MAP2_VERTEX_4 0x0DB8\n#define GL_MAP1_GRID_DOMAIN 0x0DD0\n#define GL_MAP1_GRID_SEGMENTS 0x0DD1\n#define GL_MAP2_GRID_DOMAIN 0x0DD2\n#define GL_MAP2_GRID_SEGMENTS 0x0DD3\n#define GL_TEXTURE_COMPONENTS 0x1003\n#define GL_TEXTURE_BORDER 0x1005\n#define GL_AMBIENT 0x1200\n#define GL_DIFFUSE 0x1201\n#define GL_SPECULAR 0x1202\n#define GL_POSITION 0x1203\n#define GL_SPOT_DIRECTION 0x1204\n#define GL_SPOT_EXPONENT 0x1205\n#define GL_SPOT_CUTOFF 0x1206\n#define GL_CONSTANT_ATTENUATION 0x1207\n#define GL_LINEAR_ATTENUATION 0x1208\n#define GL_QUADRATIC_ATTENUATION 0x1209\n#define GL_COMPILE 0x1300\n#define GL_COMPILE_AND_EXECUTE 0x1301\n#define GL_2_BYTES 0x1407\n#define GL_3_BYTES 0x1408\n#define GL_4_BYTES 0x1409\n#define GL_EMISSION 0x1600\n#define GL_SHININESS 0x1601\n#define GL_AMBIENT_AND_DIFFUSE 0x1602\n#define GL_COLOR_INDEXES 0x1603\n#define GL_MODELVIEW 0x1700\n#define GL_PROJECTION 0x1701\n#define GL_COLOR_INDEX 0x1900\n#define GL_LUMINANCE 0x1909\n#define GL_LUMINANCE_ALPHA 0x190A\n#define GL_BITMAP 0x1A00\n#define GL_RENDER 0x1C00\n#define GL_FEEDBACK 0x1C01\n#define GL_SELECT 0x1C02\n#define GL_FLAT 0x1D00\n#define GL_SMOOTH 0x1D01\n#define GL_S 0x2000\n#define GL_T 0x2001\n#define GL_R 0x2002\n#define GL_Q 0x2003\n#define GL_MODULATE 0x2100\n#define GL_DECAL 0x2101\n#define GL_TEXTURE_ENV_MODE 0x2200\n#define GL_TEXTURE_ENV_COLOR 0x2201\n#define GL_TEXTURE_ENV 0x2300\n#define GL_EYE_LINEAR 0x2400\n#define GL_OBJECT_LINEAR 0x2401\n#define GL_SPHERE_MAP 0x2402\n#define GL_TEXTURE_GEN_MODE 0x2500\n#define GL_OBJECT_PLANE 0x2501\n#define GL_EYE_PLANE 0x2502\n#define GL_CLAMP 0x2900\n#define GL_CLIP_PLANE0 0x3000\n#define GL_CLIP_PLANE1 0x3001\n#define GL_CLIP_PLANE2 0x3002\n#define GL_CLIP_PLANE3 0x3003\n#define GL_CLIP_PLANE4 0x3004\n#define GL_CLIP_PLANE5 0x3005\n#define GL_LIGHT0 0x4000\n#define GL_LIGHT1 0x4001\n#define GL_LIGHT2 0x4002\n#define GL_LIGHT3 0x4003\n#define GL_LIGHT4 0x4004\n#define GL_LIGHT5 0x4005\n#define GL_LIGHT6 0x4006\n#define GL_LIGHT7 0x4007\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_CLIENT_PIXEL_STORE_BIT 0x00000001\n#define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002\n#define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF\n#define GL_VERTEX_ARRAY_POINTER 0x808E\n#define GL_NORMAL_ARRAY_POINTER 0x808F\n#define GL_COLOR_ARRAY_POINTER 0x8090\n#define GL_INDEX_ARRAY_POINTER 0x8091\n#define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092\n#define GL_EDGE_FLAG_ARRAY_POINTER 0x8093\n#define GL_FEEDBACK_BUFFER_POINTER 0x0DF0\n#define GL_SELECTION_BUFFER_POINTER 0x0DF3\n#define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1\n#define GL_INDEX_LOGIC_OP 0x0BF1\n#define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B\n#define GL_FEEDBACK_BUFFER_SIZE 0x0DF1\n#define GL_FEEDBACK_BUFFER_TYPE 0x0DF2\n#define GL_SELECTION_BUFFER_SIZE 0x0DF4\n#define GL_VERTEX_ARRAY 0x8074\n#define GL_NORMAL_ARRAY 0x8075\n#define GL_COLOR_ARRAY 0x8076\n#define GL_INDEX_ARRAY 0x8077\n#define GL_TEXTURE_COORD_ARRAY 0x8078\n#define GL_EDGE_FLAG_ARRAY 0x8079\n#define GL_VERTEX_ARRAY_SIZE 0x807A\n#define GL_VERTEX_ARRAY_TYPE 0x807B\n#define GL_VERTEX_ARRAY_STRIDE 0x807C\n#define GL_NORMAL_ARRAY_TYPE 0x807E\n#define GL_NORMAL_ARRAY_STRIDE 0x807F\n#define GL_COLOR_ARRAY_SIZE 0x8081\n#define GL_COLOR_ARRAY_TYPE 0x8082\n#define GL_COLOR_ARRAY_STRIDE 0x8083\n#define GL_INDEX_ARRAY_TYPE 0x8085\n#define GL_INDEX_ARRAY_STRIDE 0x8086\n#define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088\n#define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089\n#define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A\n#define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C\n#define GL_TEXTURE_LUMINANCE_SIZE 0x8060\n#define GL_TEXTURE_INTENSITY_SIZE 0x8061\n#define GL_TEXTURE_PRIORITY 0x8066\n#define GL_TEXTURE_RESIDENT 0x8067\n#define GL_ALPHA4 0x803B\n#define GL_ALPHA8 0x803C\n#define GL_ALPHA12 0x803D\n#define GL_ALPHA16 0x803E\n#define GL_LUMINANCE4 0x803F\n#define GL_LUMINANCE8 0x8040\n#define GL_LUMINANCE12 0x8041\n#define GL_LUMINANCE16 0x8042\n#define GL_LUMINANCE4_ALPHA4 0x8043\n#define GL_LUMINANCE6_ALPHA2 0x8044\n#define GL_LUMINANCE8_ALPHA8 0x8045\n#define GL_LUMINANCE12_ALPHA4 0x8046\n#define GL_LUMINANCE12_ALPHA12 0x8047\n#define GL_LUMINANCE16_ALPHA16 0x8048\n#define GL_INTENSITY 0x8049\n#define GL_INTENSITY4 0x804A\n#define GL_INTENSITY8 0x804B\n#define GL_INTENSITY12 0x804C\n#define GL_INTENSITY16 0x804D\n#define GL_V2F 0x2A20\n#define GL_V3F 0x2A21\n#define GL_C4UB_V2F 0x2A22\n#define GL_C4UB_V3F 0x2A23\n#define GL_C3F_V3F 0x2A24\n#define GL_N3F_V3F 0x2A25\n#define GL_C4F_N3F_V3F 0x2A26\n#define GL_T2F_V3F 0x2A27\n#define GL_T4F_V4F 0x2A28\n#define GL_T2F_C4UB_V3F 0x2A29\n#define GL_T2F_C3F_V3F 0x2A2A\n#define GL_T2F_N3F_V3F 0x2A2B\n#define GL_T2F_C4F_N3F_V3F 0x2A2C\n#define GL_T4F_C4F_N3F_V4F 0x2A2D\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_RESCALE_NORMAL 0x803A\n#define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8\n#define GL_SINGLE_COLOR 0x81F9\n#define GL_SEPARATE_SPECULAR_COLOR 0x81FA\n#define GL_ALIASED_POINT_SIZE_RANGE 0x846D\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_CLIENT_ACTIVE_TEXTURE 0x84E1\n#define GL_MAX_TEXTURE_UNITS 0x84E2\n#define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3\n#define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4\n#define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5\n#define GL_TRANSPOSE_COLOR_MATRIX 0x84E6\n#define GL_MULTISAMPLE_BIT 0x20000000\n#define GL_NORMAL_MAP 0x8511\n#define GL_REFLECTION_MAP 0x8512\n#define GL_COMPRESSED_ALPHA 0x84E9\n#define GL_COMPRESSED_LUMINANCE 0x84EA\n#define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB\n#define GL_COMPRESSED_INTENSITY 0x84EC\n#define GL_COMBINE 0x8570\n#define GL_COMBINE_RGB 0x8571\n#define GL_COMBINE_ALPHA 0x8572\n#define GL_SOURCE0_RGB 0x8580\n#define GL_SOURCE1_RGB 0x8581\n#define GL_SOURCE2_RGB 0x8582\n#define GL_SOURCE0_ALPHA 0x8588\n#define GL_SOURCE1_ALPHA 0x8589\n#define GL_SOURCE2_ALPHA 0x858A\n#define GL_OPERAND0_RGB 0x8590\n#define GL_OPERAND1_RGB 0x8591\n#define GL_OPERAND2_RGB 0x8592\n#define GL_OPERAND0_ALPHA 0x8598\n#define GL_OPERAND1_ALPHA 0x8599\n#define GL_OPERAND2_ALPHA 0x859A\n#define GL_RGB_SCALE 0x8573\n#define GL_ADD_SIGNED 0x8574\n#define GL_INTERPOLATE 0x8575\n#define GL_SUBTRACT 0x84E7\n#define GL_CONSTANT 0x8576\n#define GL_PRIMARY_COLOR 0x8577\n#define GL_PREVIOUS 0x8578\n#define GL_DOT3_RGB 0x86AE\n#define GL_DOT3_RGBA 0x86AF\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_POINT_SIZE_MIN 0x8126\n#define GL_POINT_SIZE_MAX 0x8127\n#define GL_POINT_DISTANCE_ATTENUATION 0x8129\n#define GL_GENERATE_MIPMAP 0x8191\n#define GL_GENERATE_MIPMAP_HINT 0x8192\n#define GL_FOG_COORDINATE_SOURCE 0x8450\n#define GL_FOG_COORDINATE 0x8451\n#define GL_FRAGMENT_DEPTH 0x8452\n#define GL_CURRENT_FOG_COORDINATE 0x8453\n#define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454\n#define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455\n#define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456\n#define GL_FOG_COORDINATE_ARRAY 0x8457\n#define GL_COLOR_SUM 0x8458\n#define GL_CURRENT_SECONDARY_COLOR 0x8459\n#define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A\n#define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B\n#define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C\n#define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D\n#define GL_SECONDARY_COLOR_ARRAY 0x845E\n#define GL_TEXTURE_FILTER_CONTROL 0x8500\n#define GL_DEPTH_TEXTURE_MODE 0x884B\n#define GL_COMPARE_R_TO_TEXTURE 0x884E\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_VERTEX_ARRAY_BUFFER_BINDING 0x8896\n#define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897\n#define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898\n#define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899\n#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A\n#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B\n#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C\n#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D\n#define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E\n#define GL_FOG_COORD_SRC 0x8450\n#define GL_FOG_COORD 0x8451\n#define GL_CURRENT_FOG_COORD 0x8453\n#define GL_FOG_COORD_ARRAY_TYPE 0x8454\n#define GL_FOG_COORD_ARRAY_STRIDE 0x8455\n#define GL_FOG_COORD_ARRAY_POINTER 0x8456\n#define GL_FOG_COORD_ARRAY 0x8457\n#define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D\n#define GL_SRC0_RGB 0x8580\n#define GL_SRC1_RGB 0x8581\n#define GL_SRC2_RGB 0x8582\n#define GL_SRC0_ALPHA 0x8588\n#define GL_SRC2_ALPHA 0x858A\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_VERTEX_PROGRAM_TWO_SIDE 0x8643\n#define GL_POINT_SPRITE 0x8861\n#define GL_COORD_REPLACE 0x8862\n#define GL_MAX_TEXTURE_COORDS 0x8871\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_CURRENT_RASTER_SECONDARY_COLOR 0x845F\n#define GL_SLUMINANCE_ALPHA 0x8C44\n#define GL_SLUMINANCE8_ALPHA8 0x8C45\n#define GL_SLUMINANCE 0x8C46\n#define GL_SLUMINANCE8 0x8C47\n#define GL_COMPRESSED_SLUMINANCE 0x8C4A\n#define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B\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_INDEX 0x8222\n#define GL_TEXTURE_LUMINANCE_TYPE 0x8C14\n#define GL_TEXTURE_INTENSITY_TYPE 0x8C15\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_CLAMP_VERTEX_COLOR 0x891A\n#define GL_CLAMP_FRAGMENT_COLOR 0x891B\n#define GL_ALPHA_INTEGER 0x8D97\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#define GL_SAMPLE_SHADING 0x8C36\n#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37\n#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E\n#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F\n#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009\n#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A\n#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B\n#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C\n#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D\n#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E\n#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F\n#define GL_DRAW_INDIRECT_BUFFER 0x8F3F\n#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43\n#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F\n#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A\n#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B\n#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C\n#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D\n#define GL_MAX_VERTEX_STREAMS 0x8E71\n#define GL_DOUBLE_VEC2 0x8FFC\n#define GL_DOUBLE_VEC3 0x8FFD\n#define GL_DOUBLE_VEC4 0x8FFE\n#define GL_DOUBLE_MAT2 0x8F46\n#define GL_DOUBLE_MAT3 0x8F47\n#define GL_DOUBLE_MAT4 0x8F48\n#define GL_DOUBLE_MAT2x3 0x8F49\n#define GL_DOUBLE_MAT2x4 0x8F4A\n#define GL_DOUBLE_MAT3x2 0x8F4B\n#define GL_DOUBLE_MAT3x4 0x8F4C\n#define GL_DOUBLE_MAT4x2 0x8F4D\n#define GL_DOUBLE_MAT4x3 0x8F4E\n#define GL_ACTIVE_SUBROUTINES 0x8DE5\n#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6\n#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47\n#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48\n#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49\n#define GL_MAX_SUBROUTINES 0x8DE7\n#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8\n#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A\n#define GL_COMPATIBLE_SUBROUTINES 0x8E4B\n#define GL_PATCHES 0x000E\n#define GL_PATCH_VERTICES 0x8E72\n#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73\n#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74\n#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75\n#define GL_TESS_GEN_MODE 0x8E76\n#define GL_TESS_GEN_SPACING 0x8E77\n#define GL_TESS_GEN_VERTEX_ORDER 0x8E78\n#define GL_TESS_GEN_POINT_MODE 0x8E79\n#define GL_ISOLINES 0x8E7A\n#define GL_FRACTIONAL_ODD 0x8E7B\n#define GL_FRACTIONAL_EVEN 0x8E7C\n#define GL_MAX_PATCH_VERTICES 0x8E7D\n#define GL_MAX_TESS_GEN_LEVEL 0x8E7E\n#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F\n#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80\n#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81\n#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82\n#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83\n#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84\n#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85\n#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86\n#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89\n#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A\n#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C\n#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D\n#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E\n#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1\n#define GL_TESS_EVALUATION_SHADER 0x8E87\n#define GL_TESS_CONTROL_SHADER 0x8E88\n#define GL_TRANSFORM_FEEDBACK 0x8E22\n#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23\n#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24\n#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25\n#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70\n#define GL_FIXED 0x140C\n#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A\n#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B\n#define GL_LOW_FLOAT 0x8DF0\n#define GL_MEDIUM_FLOAT 0x8DF1\n#define GL_HIGH_FLOAT 0x8DF2\n#define GL_LOW_INT 0x8DF3\n#define GL_MEDIUM_INT 0x8DF4\n#define GL_HIGH_INT 0x8DF5\n#define GL_SHADER_COMPILER 0x8DFA\n#define GL_SHADER_BINARY_FORMATS 0x8DF8\n#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9\n#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB\n#define GL_MAX_VARYING_VECTORS 0x8DFC\n#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD\n#define GL_RGB565 0x8D62\n#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257\n#define GL_PROGRAM_BINARY_LENGTH 0x8741\n#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE\n#define GL_PROGRAM_BINARY_FORMATS 0x87FF\n#define GL_VERTEX_SHADER_BIT 0x00000001\n#define GL_FRAGMENT_SHADER_BIT 0x00000002\n#define GL_GEOMETRY_SHADER_BIT 0x00000004\n#define GL_TESS_CONTROL_SHADER_BIT 0x00000008\n#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010\n#define GL_ALL_SHADER_BITS 0xFFFFFFFF\n#define GL_PROGRAM_SEPARABLE 0x8258\n#define GL_ACTIVE_PROGRAM 0x8259\n#define GL_PROGRAM_PIPELINE_BINDING 0x825A\n#define GL_MAX_VIEWPORTS 0x825B\n#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C\n#define GL_VIEWPORT_BOUNDS_RANGE 0x825D\n#define GL_LAYER_PROVOKING_VERTEX 0x825E\n#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F\n#define GL_UNDEFINED_VERTEX 0x8260\n#define GL_COPY_READ_BUFFER_BINDING 0x8F36\n#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37\n#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24\n#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23\n#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127\n#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128\n#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129\n#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A\n#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B\n#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C\n#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D\n#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E\n#define GL_NUM_SAMPLE_COUNTS 0x9380\n#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC\n#define GL_ATOMIC_COUNTER_BUFFER 0x92C0\n#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1\n#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2\n#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3\n#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4\n#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5\n#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB\n#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC\n#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD\n#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE\n#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF\n#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0\n#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1\n#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2\n#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3\n#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4\n#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5\n#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6\n#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7\n#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8\n#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC\n#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9\n#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA\n#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB\n#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001\n#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002\n#define GL_UNIFORM_BARRIER_BIT 0x00000004\n#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008\n#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020\n#define GL_COMMAND_BARRIER_BIT 0x00000040\n#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080\n#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100\n#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200\n#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400\n#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800\n#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000\n#define GL_ALL_BARRIER_BITS 0xFFFFFFFF\n#define GL_MAX_IMAGE_UNITS 0x8F38\n#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39\n#define GL_IMAGE_BINDING_NAME 0x8F3A\n#define GL_IMAGE_BINDING_LEVEL 0x8F3B\n#define GL_IMAGE_BINDING_LAYERED 0x8F3C\n#define GL_IMAGE_BINDING_LAYER 0x8F3D\n#define GL_IMAGE_BINDING_ACCESS 0x8F3E\n#define GL_IMAGE_1D 0x904C\n#define GL_IMAGE_2D 0x904D\n#define GL_IMAGE_3D 0x904E\n#define GL_IMAGE_2D_RECT 0x904F\n#define GL_IMAGE_CUBE 0x9050\n#define GL_IMAGE_BUFFER 0x9051\n#define GL_IMAGE_1D_ARRAY 0x9052\n#define GL_IMAGE_2D_ARRAY 0x9053\n#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054\n#define GL_IMAGE_2D_MULTISAMPLE 0x9055\n#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056\n#define GL_INT_IMAGE_1D 0x9057\n#define GL_INT_IMAGE_2D 0x9058\n#define GL_INT_IMAGE_3D 0x9059\n#define GL_INT_IMAGE_2D_RECT 0x905A\n#define GL_INT_IMAGE_CUBE 0x905B\n#define GL_INT_IMAGE_BUFFER 0x905C\n#define GL_INT_IMAGE_1D_ARRAY 0x905D\n#define GL_INT_IMAGE_2D_ARRAY 0x905E\n#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F\n#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060\n#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061\n#define GL_UNSIGNED_INT_IMAGE_1D 0x9062\n#define GL_UNSIGNED_INT_IMAGE_2D 0x9063\n#define GL_UNSIGNED_INT_IMAGE_3D 0x9064\n#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065\n#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066\n#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067\n#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068\n#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069\n#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A\n#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B\n#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C\n#define GL_MAX_IMAGE_SAMPLES 0x906D\n#define GL_IMAGE_BINDING_FORMAT 0x906E\n#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7\n#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8\n#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9\n#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA\n#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB\n#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC\n#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD\n#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE\n#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF\n#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C\n#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D\n#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E\n#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F\n#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F\n#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9\n#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E\n#define GL_COMPRESSED_RGB8_ETC2 0x9274\n#define GL_COMPRESSED_SRGB8_ETC2 0x9275\n#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276\n#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277\n#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278\n#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279\n#define GL_COMPRESSED_R11_EAC 0x9270\n#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271\n#define GL_COMPRESSED_RG11_EAC 0x9272\n#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273\n#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69\n#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A\n#define GL_MAX_ELEMENT_INDEX 0x8D6B\n#define GL_COMPUTE_SHADER 0x91B9\n#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB\n#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC\n#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD\n#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262\n#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263\n#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264\n#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265\n#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266\n#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB\n#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE\n#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF\n#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED\n#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE\n#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF\n#define GL_COMPUTE_SHADER_BIT 0x00000020\n#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242\n#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243\n#define GL_DEBUG_CALLBACK_FUNCTION 0x8244\n#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245\n#define GL_DEBUG_SOURCE_API 0x8246\n#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247\n#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248\n#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249\n#define GL_DEBUG_SOURCE_APPLICATION 0x824A\n#define GL_DEBUG_SOURCE_OTHER 0x824B\n#define GL_DEBUG_TYPE_ERROR 0x824C\n#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D\n#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E\n#define GL_DEBUG_TYPE_PORTABILITY 0x824F\n#define GL_DEBUG_TYPE_PERFORMANCE 0x8250\n#define GL_DEBUG_TYPE_OTHER 0x8251\n#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143\n#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144\n#define GL_DEBUG_LOGGED_MESSAGES 0x9145\n#define GL_DEBUG_SEVERITY_HIGH 0x9146\n#define GL_DEBUG_SEVERITY_MEDIUM 0x9147\n#define GL_DEBUG_SEVERITY_LOW 0x9148\n#define GL_DEBUG_TYPE_MARKER 0x8268\n#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269\n#define GL_DEBUG_TYPE_POP_GROUP 0x826A\n#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B\n#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C\n#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D\n#define GL_BUFFER 0x82E0\n#define GL_SHADER 0x82E1\n#define GL_PROGRAM 0x82E2\n#define GL_QUERY 0x82E3\n#define GL_PROGRAM_PIPELINE 0x82E4\n#define GL_SAMPLER 0x82E6\n#define GL_MAX_LABEL_LENGTH 0x82E8\n#define GL_DEBUG_OUTPUT 0x92E0\n#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002\n#define GL_MAX_UNIFORM_LOCATIONS 0x826E\n#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310\n#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311\n#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312\n#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313\n#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314\n#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315\n#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316\n#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317\n#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318\n#define GL_INTERNALFORMAT_SUPPORTED 0x826F\n#define GL_INTERNALFORMAT_PREFERRED 0x8270\n#define GL_INTERNALFORMAT_RED_SIZE 0x8271\n#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272\n#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273\n#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274\n#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275\n#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276\n#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277\n#define GL_INTERNALFORMAT_RED_TYPE 0x8278\n#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279\n#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A\n#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B\n#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C\n#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D\n#define GL_MAX_WIDTH 0x827E\n#define GL_MAX_HEIGHT 0x827F\n#define GL_MAX_DEPTH 0x8280\n#define GL_MAX_LAYERS 0x8281\n#define GL_MAX_COMBINED_DIMENSIONS 0x8282\n#define GL_COLOR_COMPONENTS 0x8283\n#define GL_DEPTH_COMPONENTS 0x8284\n#define GL_STENCIL_COMPONENTS 0x8285\n#define GL_COLOR_RENDERABLE 0x8286\n#define GL_DEPTH_RENDERABLE 0x8287\n#define GL_STENCIL_RENDERABLE 0x8288\n#define GL_FRAMEBUFFER_RENDERABLE 0x8289\n#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A\n#define GL_FRAMEBUFFER_BLEND 0x828B\n#define GL_READ_PIXELS 0x828C\n#define GL_READ_PIXELS_FORMAT 0x828D\n#define GL_READ_PIXELS_TYPE 0x828E\n#define GL_TEXTURE_IMAGE_FORMAT 0x828F\n#define GL_TEXTURE_IMAGE_TYPE 0x8290\n#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291\n#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292\n#define GL_MIPMAP 0x8293\n#define GL_MANUAL_GENERATE_MIPMAP 0x8294\n#define GL_AUTO_GENERATE_MIPMAP 0x8295\n#define GL_COLOR_ENCODING 0x8296\n#define GL_SRGB_READ 0x8297\n#define GL_SRGB_WRITE 0x8298\n#define GL_FILTER 0x829A\n#define GL_VERTEX_TEXTURE 0x829B\n#define GL_TESS_CONTROL_TEXTURE 0x829C\n#define GL_TESS_EVALUATION_TEXTURE 0x829D\n#define GL_GEOMETRY_TEXTURE 0x829E\n#define GL_FRAGMENT_TEXTURE 0x829F\n#define GL_COMPUTE_TEXTURE 0x82A0\n#define GL_TEXTURE_SHADOW 0x82A1\n#define GL_TEXTURE_GATHER 0x82A2\n#define GL_TEXTURE_GATHER_SHADOW 0x82A3\n#define GL_SHADER_IMAGE_LOAD 0x82A4\n#define GL_SHADER_IMAGE_STORE 0x82A5\n#define GL_SHADER_IMAGE_ATOMIC 0x82A6\n#define GL_IMAGE_TEXEL_SIZE 0x82A7\n#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8\n#define GL_IMAGE_PIXEL_FORMAT 0x82A9\n#define GL_IMAGE_PIXEL_TYPE 0x82AA\n#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC\n#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD\n#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE\n#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF\n#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1\n#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2\n#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3\n#define GL_CLEAR_BUFFER 0x82B4\n#define GL_TEXTURE_VIEW 0x82B5\n#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6\n#define GL_FULL_SUPPORT 0x82B7\n#define GL_CAVEAT_SUPPORT 0x82B8\n#define GL_IMAGE_CLASS_4_X_32 0x82B9\n#define GL_IMAGE_CLASS_2_X_32 0x82BA\n#define GL_IMAGE_CLASS_1_X_32 0x82BB\n#define GL_IMAGE_CLASS_4_X_16 0x82BC\n#define GL_IMAGE_CLASS_2_X_16 0x82BD\n#define GL_IMAGE_CLASS_1_X_16 0x82BE\n#define GL_IMAGE_CLASS_4_X_8 0x82BF\n#define GL_IMAGE_CLASS_2_X_8 0x82C0\n#define GL_IMAGE_CLASS_1_X_8 0x82C1\n#define GL_IMAGE_CLASS_11_11_10 0x82C2\n#define GL_IMAGE_CLASS_10_10_10_2 0x82C3\n#define GL_VIEW_CLASS_128_BITS 0x82C4\n#define GL_VIEW_CLASS_96_BITS 0x82C5\n#define GL_VIEW_CLASS_64_BITS 0x82C6\n#define GL_VIEW_CLASS_48_BITS 0x82C7\n#define GL_VIEW_CLASS_32_BITS 0x82C8\n#define GL_VIEW_CLASS_24_BITS 0x82C9\n#define GL_VIEW_CLASS_16_BITS 0x82CA\n#define GL_VIEW_CLASS_8_BITS 0x82CB\n#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC\n#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD\n#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE\n#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF\n#define GL_VIEW_CLASS_RGTC1_RED 0x82D0\n#define GL_VIEW_CLASS_RGTC2_RG 0x82D1\n#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2\n#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3\n#define GL_UNIFORM 0x92E1\n#define GL_UNIFORM_BLOCK 0x92E2\n#define GL_PROGRAM_INPUT 0x92E3\n#define GL_PROGRAM_OUTPUT 0x92E4\n#define GL_BUFFER_VARIABLE 0x92E5\n#define GL_SHADER_STORAGE_BLOCK 0x92E6\n#define GL_VERTEX_SUBROUTINE 0x92E8\n#define GL_TESS_CONTROL_SUBROUTINE 0x92E9\n#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA\n#define GL_GEOMETRY_SUBROUTINE 0x92EB\n#define GL_FRAGMENT_SUBROUTINE 0x92EC\n#define GL_COMPUTE_SUBROUTINE 0x92ED\n#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE\n#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF\n#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0\n#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1\n#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2\n#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3\n#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4\n#define GL_ACTIVE_RESOURCES 0x92F5\n#define GL_MAX_NAME_LENGTH 0x92F6\n#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7\n#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8\n#define GL_NAME_LENGTH 0x92F9\n#define GL_TYPE 0x92FA\n#define GL_ARRAY_SIZE 0x92FB\n#define GL_OFFSET 0x92FC\n#define GL_BLOCK_INDEX 0x92FD\n#define GL_ARRAY_STRIDE 0x92FE\n#define GL_MATRIX_STRIDE 0x92FF\n#define GL_IS_ROW_MAJOR 0x9300\n#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301\n#define GL_BUFFER_BINDING 0x9302\n#define GL_BUFFER_DATA_SIZE 0x9303\n#define GL_NUM_ACTIVE_VARIABLES 0x9304\n#define GL_ACTIVE_VARIABLES 0x9305\n#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306\n#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307\n#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308\n#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309\n#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A\n#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B\n#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C\n#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D\n#define GL_LOCATION 0x930E\n#define GL_LOCATION_INDEX 0x930F\n#define GL_IS_PER_PATCH 0x92E7\n#define GL_SHADER_STORAGE_BUFFER 0x90D2\n#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3\n#define GL_SHADER_STORAGE_BUFFER_START 0x90D4\n#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5\n#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6\n#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7\n#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8\n#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9\n#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA\n#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB\n#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC\n#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD\n#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE\n#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF\n#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000\n#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39\n#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA\n#define GL_TEXTURE_BUFFER_OFFSET 0x919D\n#define GL_TEXTURE_BUFFER_SIZE 0x919E\n#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F\n#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB\n#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC\n#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD\n#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE\n#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF\n#define GL_VERTEX_ATTRIB_BINDING 0x82D4\n#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5\n#define GL_VERTEX_BINDING_DIVISOR 0x82D6\n#define GL_VERTEX_BINDING_OFFSET 0x82D7\n#define GL_VERTEX_BINDING_STRIDE 0x82D8\n#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9\n#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA\n#define GL_VERTEX_BINDING_BUFFER 0x8F4F\n#define GL_DISPLAY_LIST 0x82E7\n#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5\n#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221\n#define GL_TEXTURE_BUFFER_BINDING 0x8C2A\n#define GL_MAP_PERSISTENT_BIT 0x0040\n#define GL_MAP_COHERENT_BIT 0x0080\n#define GL_DYNAMIC_STORAGE_BIT 0x0100\n#define GL_CLIENT_STORAGE_BIT 0x0200\n#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000\n#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F\n#define GL_BUFFER_STORAGE_FLAGS 0x8220\n#define GL_CLEAR_TEXTURE 0x9365\n#define GL_LOCATION_COMPONENT 0x934A\n#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B\n#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C\n#define GL_QUERY_BUFFER 0x9192\n#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000\n#define GL_QUERY_BUFFER_BINDING 0x9193\n#define GL_QUERY_RESULT_NO_WAIT 0x9194\n#define GL_MIRROR_CLAMP_TO_EDGE 0x8743\n#define GL_CONTEXT_LOST 0x0507\n#define GL_NEGATIVE_ONE_TO_ONE 0x935E\n#define GL_ZERO_TO_ONE 0x935F\n#define GL_CLIP_ORIGIN 0x935C\n#define GL_CLIP_DEPTH_MODE 0x935D\n#define GL_QUERY_WAIT_INVERTED 0x8E17\n#define GL_QUERY_NO_WAIT_INVERTED 0x8E18\n#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19\n#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A\n#define GL_MAX_CULL_DISTANCES 0x82F9\n#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA\n#define GL_TEXTURE_TARGET 0x1006\n#define GL_QUERY_TARGET 0x82EA\n#define GL_GUILTY_CONTEXT_RESET 0x8253\n#define GL_INNOCENT_CONTEXT_RESET 0x8254\n#define GL_UNKNOWN_CONTEXT_RESET 0x8255\n#define GL_RESET_NOTIFICATION_STRATEGY 0x8256\n#define GL_LOSE_CONTEXT_ON_RESET 0x8252\n#define GL_NO_RESET_NOTIFICATION 0x8261\n#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004\n#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB\n#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC\n#define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551\n#define GL_SPIR_V_BINARY 0x9552\n#define GL_PARAMETER_BUFFER 0x80EE\n#define GL_PARAMETER_BUFFER_BINDING 0x80EF\n#define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008\n#define GL_VERTICES_SUBMITTED 0x82EE\n#define GL_PRIMITIVES_SUBMITTED 0x82EF\n#define GL_VERTEX_SHADER_INVOCATIONS 0x82F0\n#define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1\n#define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2\n#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3\n#define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4\n#define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5\n#define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6\n#define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7\n#define GL_POLYGON_OFFSET_CLAMP 0x8E1B\n#define GL_SPIR_V_EXTENSIONS 0x9553\n#define GL_NUM_SPIR_V_EXTENSIONS 0x9554\n#define GL_TEXTURE_MAX_ANISOTROPY 0x84FE\n#define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF\n#define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC\n#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED\n#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9\n#define GL_MULTISAMPLE_LINE_WIDTH_RANGE 0x9381\n#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY 0x9382\n#define GL_MULTIPLY 0x9294\n#define GL_SCREEN 0x9295\n#define GL_OVERLAY 0x9296\n#define GL_DARKEN 0x9297\n#define GL_LIGHTEN 0x9298\n#define GL_COLORDODGE 0x9299\n#define GL_COLORBURN 0x929A\n#define GL_HARDLIGHT 0x929B\n#define GL_SOFTLIGHT 0x929C\n#define GL_DIFFERENCE 0x929E\n#define GL_EXCLUSION 0x92A0\n#define GL_HSL_HUE 0x92AD\n#define GL_HSL_SATURATION 0x92AE\n#define GL_HSL_COLOR 0x92AF\n#define GL_HSL_LUMINOSITY 0x92B0\n#define GL_PRIMITIVE_BOUNDING_BOX 0x92BE\n#define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0\n#define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1\n#define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2\n#define GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3\n#define GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4\n#define GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5\n#define GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6\n#define GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7\n#define GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8\n#define GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9\n#define GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA\n#define GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB\n#define GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC\n#define GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD\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\ntypedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode);\nGLAPI PFNGLNEWLISTPROC glad_glNewList;\n#define glNewList glad_glNewList\ntypedef void (APIENTRYP PFNGLENDLISTPROC)(void);\nGLAPI PFNGLENDLISTPROC glad_glEndList;\n#define glEndList glad_glEndList\ntypedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list);\nGLAPI PFNGLCALLLISTPROC glad_glCallList;\n#define glCallList glad_glCallList\ntypedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void *lists);\nGLAPI PFNGLCALLLISTSPROC glad_glCallLists;\n#define glCallLists glad_glCallLists\ntypedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range);\nGLAPI PFNGLDELETELISTSPROC glad_glDeleteLists;\n#define glDeleteLists glad_glDeleteLists\ntypedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range);\nGLAPI PFNGLGENLISTSPROC glad_glGenLists;\n#define glGenLists glad_glGenLists\ntypedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base);\nGLAPI PFNGLLISTBASEPROC glad_glListBase;\n#define glListBase glad_glListBase\ntypedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode);\nGLAPI PFNGLBEGINPROC glad_glBegin;\n#define glBegin glad_glBegin\ntypedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);\nGLAPI PFNGLBITMAPPROC glad_glBitmap;\n#define glBitmap glad_glBitmap\ntypedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue);\nGLAPI PFNGLCOLOR3BPROC glad_glColor3b;\n#define glColor3b glad_glColor3b\ntypedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte *v);\nGLAPI PFNGLCOLOR3BVPROC glad_glColor3bv;\n#define glColor3bv glad_glColor3bv\ntypedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue);\nGLAPI PFNGLCOLOR3DPROC glad_glColor3d;\n#define glColor3d glad_glColor3d\ntypedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble *v);\nGLAPI PFNGLCOLOR3DVPROC glad_glColor3dv;\n#define glColor3dv glad_glColor3dv\ntypedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue);\nGLAPI PFNGLCOLOR3FPROC glad_glColor3f;\n#define glColor3f glad_glColor3f\ntypedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat *v);\nGLAPI PFNGLCOLOR3FVPROC glad_glColor3fv;\n#define glColor3fv glad_glColor3fv\ntypedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue);\nGLAPI PFNGLCOLOR3IPROC glad_glColor3i;\n#define glColor3i glad_glColor3i\ntypedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint *v);\nGLAPI PFNGLCOLOR3IVPROC glad_glColor3iv;\n#define glColor3iv glad_glColor3iv\ntypedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue);\nGLAPI PFNGLCOLOR3SPROC glad_glColor3s;\n#define glColor3s glad_glColor3s\ntypedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort *v);\nGLAPI PFNGLCOLOR3SVPROC glad_glColor3sv;\n#define glColor3sv glad_glColor3sv\ntypedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue);\nGLAPI PFNGLCOLOR3UBPROC glad_glColor3ub;\n#define glColor3ub glad_glColor3ub\ntypedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte *v);\nGLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv;\n#define glColor3ubv glad_glColor3ubv\ntypedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue);\nGLAPI PFNGLCOLOR3UIPROC glad_glColor3ui;\n#define glColor3ui glad_glColor3ui\ntypedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint *v);\nGLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv;\n#define glColor3uiv glad_glColor3uiv\ntypedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue);\nGLAPI PFNGLCOLOR3USPROC glad_glColor3us;\n#define glColor3us glad_glColor3us\ntypedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort *v);\nGLAPI PFNGLCOLOR3USVPROC glad_glColor3usv;\n#define glColor3usv glad_glColor3usv\ntypedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);\nGLAPI PFNGLCOLOR4BPROC glad_glColor4b;\n#define glColor4b glad_glColor4b\ntypedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte *v);\nGLAPI PFNGLCOLOR4BVPROC glad_glColor4bv;\n#define glColor4bv glad_glColor4bv\ntypedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);\nGLAPI PFNGLCOLOR4DPROC glad_glColor4d;\n#define glColor4d glad_glColor4d\ntypedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble *v);\nGLAPI PFNGLCOLOR4DVPROC glad_glColor4dv;\n#define glColor4dv glad_glColor4dv\ntypedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI PFNGLCOLOR4FPROC glad_glColor4f;\n#define glColor4f glad_glColor4f\ntypedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat *v);\nGLAPI PFNGLCOLOR4FVPROC glad_glColor4fv;\n#define glColor4fv glad_glColor4fv\ntypedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha);\nGLAPI PFNGLCOLOR4IPROC glad_glColor4i;\n#define glColor4i glad_glColor4i\ntypedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint *v);\nGLAPI PFNGLCOLOR4IVPROC glad_glColor4iv;\n#define glColor4iv glad_glColor4iv\ntypedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha);\nGLAPI PFNGLCOLOR4SPROC glad_glColor4s;\n#define glColor4s glad_glColor4s\ntypedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort *v);\nGLAPI PFNGLCOLOR4SVPROC glad_glColor4sv;\n#define glColor4sv glad_glColor4sv\ntypedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);\nGLAPI PFNGLCOLOR4UBPROC glad_glColor4ub;\n#define glColor4ub glad_glColor4ub\ntypedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte *v);\nGLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv;\n#define glColor4ubv glad_glColor4ubv\ntypedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha);\nGLAPI PFNGLCOLOR4UIPROC glad_glColor4ui;\n#define glColor4ui glad_glColor4ui\ntypedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint *v);\nGLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv;\n#define glColor4uiv glad_glColor4uiv\ntypedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha);\nGLAPI PFNGLCOLOR4USPROC glad_glColor4us;\n#define glColor4us glad_glColor4us\ntypedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort *v);\nGLAPI PFNGLCOLOR4USVPROC glad_glColor4usv;\n#define glColor4usv glad_glColor4usv\ntypedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag);\nGLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag;\n#define glEdgeFlag glad_glEdgeFlag\ntypedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean *flag);\nGLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv;\n#define glEdgeFlagv glad_glEdgeFlagv\ntypedef void (APIENTRYP PFNGLENDPROC)(void);\nGLAPI PFNGLENDPROC glad_glEnd;\n#define glEnd glad_glEnd\ntypedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c);\nGLAPI PFNGLINDEXDPROC glad_glIndexd;\n#define glIndexd glad_glIndexd\ntypedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble *c);\nGLAPI PFNGLINDEXDVPROC glad_glIndexdv;\n#define glIndexdv glad_glIndexdv\ntypedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c);\nGLAPI PFNGLINDEXFPROC glad_glIndexf;\n#define glIndexf glad_glIndexf\ntypedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat *c);\nGLAPI PFNGLINDEXFVPROC glad_glIndexfv;\n#define glIndexfv glad_glIndexfv\ntypedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c);\nGLAPI PFNGLINDEXIPROC glad_glIndexi;\n#define glIndexi glad_glIndexi\ntypedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint *c);\nGLAPI PFNGLINDEXIVPROC glad_glIndexiv;\n#define glIndexiv glad_glIndexiv\ntypedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c);\nGLAPI PFNGLINDEXSPROC glad_glIndexs;\n#define glIndexs glad_glIndexs\ntypedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort *c);\nGLAPI PFNGLINDEXSVPROC glad_glIndexsv;\n#define glIndexsv glad_glIndexsv\ntypedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz);\nGLAPI PFNGLNORMAL3BPROC glad_glNormal3b;\n#define glNormal3b glad_glNormal3b\ntypedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte *v);\nGLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv;\n#define glNormal3bv glad_glNormal3bv\ntypedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz);\nGLAPI PFNGLNORMAL3DPROC glad_glNormal3d;\n#define glNormal3d glad_glNormal3d\ntypedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble *v);\nGLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv;\n#define glNormal3dv glad_glNormal3dv\ntypedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz);\nGLAPI PFNGLNORMAL3FPROC glad_glNormal3f;\n#define glNormal3f glad_glNormal3f\ntypedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat *v);\nGLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv;\n#define glNormal3fv glad_glNormal3fv\ntypedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz);\nGLAPI PFNGLNORMAL3IPROC glad_glNormal3i;\n#define glNormal3i glad_glNormal3i\ntypedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint *v);\nGLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv;\n#define glNormal3iv glad_glNormal3iv\ntypedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz);\nGLAPI PFNGLNORMAL3SPROC glad_glNormal3s;\n#define glNormal3s glad_glNormal3s\ntypedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort *v);\nGLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv;\n#define glNormal3sv glad_glNormal3sv\ntypedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y);\nGLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d;\n#define glRasterPos2d glad_glRasterPos2d\ntypedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble *v);\nGLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv;\n#define glRasterPos2dv glad_glRasterPos2dv\ntypedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y);\nGLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f;\n#define glRasterPos2f glad_glRasterPos2f\ntypedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat *v);\nGLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv;\n#define glRasterPos2fv glad_glRasterPos2fv\ntypedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y);\nGLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i;\n#define glRasterPos2i glad_glRasterPos2i\ntypedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint *v);\nGLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv;\n#define glRasterPos2iv glad_glRasterPos2iv\ntypedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y);\nGLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s;\n#define glRasterPos2s glad_glRasterPos2s\ntypedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort *v);\nGLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv;\n#define glRasterPos2sv glad_glRasterPos2sv\ntypedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d;\n#define glRasterPos3d glad_glRasterPos3d\ntypedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble *v);\nGLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv;\n#define glRasterPos3dv glad_glRasterPos3dv\ntypedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f;\n#define glRasterPos3f glad_glRasterPos3f\ntypedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat *v);\nGLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv;\n#define glRasterPos3fv glad_glRasterPos3fv\ntypedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z);\nGLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i;\n#define glRasterPos3i glad_glRasterPos3i\ntypedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint *v);\nGLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv;\n#define glRasterPos3iv glad_glRasterPos3iv\ntypedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z);\nGLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s;\n#define glRasterPos3s glad_glRasterPos3s\ntypedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort *v);\nGLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv;\n#define glRasterPos3sv glad_glRasterPos3sv\ntypedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d;\n#define glRasterPos4d glad_glRasterPos4d\ntypedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble *v);\nGLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv;\n#define glRasterPos4dv glad_glRasterPos4dv\ntypedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f;\n#define glRasterPos4f glad_glRasterPos4f\ntypedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat *v);\nGLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv;\n#define glRasterPos4fv glad_glRasterPos4fv\ntypedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w);\nGLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i;\n#define glRasterPos4i glad_glRasterPos4i\ntypedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint *v);\nGLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv;\n#define glRasterPos4iv glad_glRasterPos4iv\ntypedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s;\n#define glRasterPos4s glad_glRasterPos4s\ntypedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort *v);\nGLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv;\n#define glRasterPos4sv glad_glRasterPos4sv\ntypedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);\nGLAPI PFNGLRECTDPROC glad_glRectd;\n#define glRectd glad_glRectd\ntypedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble *v1, const GLdouble *v2);\nGLAPI PFNGLRECTDVPROC glad_glRectdv;\n#define glRectdv glad_glRectdv\ntypedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);\nGLAPI PFNGLRECTFPROC glad_glRectf;\n#define glRectf glad_glRectf\ntypedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat *v1, const GLfloat *v2);\nGLAPI PFNGLRECTFVPROC glad_glRectfv;\n#define glRectfv glad_glRectfv\ntypedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2);\nGLAPI PFNGLRECTIPROC glad_glRecti;\n#define glRecti glad_glRecti\ntypedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint *v1, const GLint *v2);\nGLAPI PFNGLRECTIVPROC glad_glRectiv;\n#define glRectiv glad_glRectiv\ntypedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2);\nGLAPI PFNGLRECTSPROC glad_glRects;\n#define glRects glad_glRects\ntypedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort *v1, const GLshort *v2);\nGLAPI PFNGLRECTSVPROC glad_glRectsv;\n#define glRectsv glad_glRectsv\ntypedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s);\nGLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d;\n#define glTexCoord1d glad_glTexCoord1d\ntypedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble *v);\nGLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv;\n#define glTexCoord1dv glad_glTexCoord1dv\ntypedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s);\nGLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f;\n#define glTexCoord1f glad_glTexCoord1f\ntypedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat *v);\nGLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv;\n#define glTexCoord1fv glad_glTexCoord1fv\ntypedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s);\nGLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i;\n#define glTexCoord1i glad_glTexCoord1i\ntypedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint *v);\nGLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv;\n#define glTexCoord1iv glad_glTexCoord1iv\ntypedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s);\nGLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s;\n#define glTexCoord1s glad_glTexCoord1s\ntypedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort *v);\nGLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv;\n#define glTexCoord1sv glad_glTexCoord1sv\ntypedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t);\nGLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d;\n#define glTexCoord2d glad_glTexCoord2d\ntypedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble *v);\nGLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv;\n#define glTexCoord2dv glad_glTexCoord2dv\ntypedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t);\nGLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f;\n#define glTexCoord2f glad_glTexCoord2f\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat *v);\nGLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv;\n#define glTexCoord2fv glad_glTexCoord2fv\ntypedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t);\nGLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i;\n#define glTexCoord2i glad_glTexCoord2i\ntypedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint *v);\nGLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv;\n#define glTexCoord2iv glad_glTexCoord2iv\ntypedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t);\nGLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s;\n#define glTexCoord2s glad_glTexCoord2s\ntypedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort *v);\nGLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv;\n#define glTexCoord2sv glad_glTexCoord2sv\ntypedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r);\nGLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d;\n#define glTexCoord3d glad_glTexCoord3d\ntypedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble *v);\nGLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv;\n#define glTexCoord3dv glad_glTexCoord3dv\ntypedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r);\nGLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f;\n#define glTexCoord3f glad_glTexCoord3f\ntypedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat *v);\nGLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv;\n#define glTexCoord3fv glad_glTexCoord3fv\ntypedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r);\nGLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i;\n#define glTexCoord3i glad_glTexCoord3i\ntypedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint *v);\nGLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv;\n#define glTexCoord3iv glad_glTexCoord3iv\ntypedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r);\nGLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s;\n#define glTexCoord3s glad_glTexCoord3s\ntypedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort *v);\nGLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv;\n#define glTexCoord3sv glad_glTexCoord3sv\ntypedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q);\nGLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d;\n#define glTexCoord4d glad_glTexCoord4d\ntypedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble *v);\nGLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv;\n#define glTexCoord4dv glad_glTexCoord4dv\ntypedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q);\nGLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f;\n#define glTexCoord4f glad_glTexCoord4f\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat *v);\nGLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv;\n#define glTexCoord4fv glad_glTexCoord4fv\ntypedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q);\nGLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i;\n#define glTexCoord4i glad_glTexCoord4i\ntypedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint *v);\nGLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv;\n#define glTexCoord4iv glad_glTexCoord4iv\ntypedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q);\nGLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s;\n#define glTexCoord4s glad_glTexCoord4s\ntypedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort *v);\nGLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv;\n#define glTexCoord4sv glad_glTexCoord4sv\ntypedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y);\nGLAPI PFNGLVERTEX2DPROC glad_glVertex2d;\n#define glVertex2d glad_glVertex2d\ntypedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble *v);\nGLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv;\n#define glVertex2dv glad_glVertex2dv\ntypedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y);\nGLAPI PFNGLVERTEX2FPROC glad_glVertex2f;\n#define glVertex2f glad_glVertex2f\ntypedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat *v);\nGLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv;\n#define glVertex2fv glad_glVertex2fv\ntypedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y);\nGLAPI PFNGLVERTEX2IPROC glad_glVertex2i;\n#define glVertex2i glad_glVertex2i\ntypedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint *v);\nGLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv;\n#define glVertex2iv glad_glVertex2iv\ntypedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y);\nGLAPI PFNGLVERTEX2SPROC glad_glVertex2s;\n#define glVertex2s glad_glVertex2s\ntypedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort *v);\nGLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv;\n#define glVertex2sv glad_glVertex2sv\ntypedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLVERTEX3DPROC glad_glVertex3d;\n#define glVertex3d glad_glVertex3d\ntypedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble *v);\nGLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv;\n#define glVertex3dv glad_glVertex3dv\ntypedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLVERTEX3FPROC glad_glVertex3f;\n#define glVertex3f glad_glVertex3f\ntypedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat *v);\nGLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv;\n#define glVertex3fv glad_glVertex3fv\ntypedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z);\nGLAPI PFNGLVERTEX3IPROC glad_glVertex3i;\n#define glVertex3i glad_glVertex3i\ntypedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint *v);\nGLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv;\n#define glVertex3iv glad_glVertex3iv\ntypedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z);\nGLAPI PFNGLVERTEX3SPROC glad_glVertex3s;\n#define glVertex3s glad_glVertex3s\ntypedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort *v);\nGLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv;\n#define glVertex3sv glad_glVertex3sv\ntypedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI PFNGLVERTEX4DPROC glad_glVertex4d;\n#define glVertex4d glad_glVertex4d\ntypedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble *v);\nGLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv;\n#define glVertex4dv glad_glVertex4dv\ntypedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI PFNGLVERTEX4FPROC glad_glVertex4f;\n#define glVertex4f glad_glVertex4f\ntypedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat *v);\nGLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv;\n#define glVertex4fv glad_glVertex4fv\ntypedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w);\nGLAPI PFNGLVERTEX4IPROC glad_glVertex4i;\n#define glVertex4i glad_glVertex4i\ntypedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint *v);\nGLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv;\n#define glVertex4iv glad_glVertex4iv\ntypedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI PFNGLVERTEX4SPROC glad_glVertex4s;\n#define glVertex4s glad_glVertex4s\ntypedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort *v);\nGLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv;\n#define glVertex4sv glad_glVertex4sv\ntypedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble *equation);\nGLAPI PFNGLCLIPPLANEPROC glad_glClipPlane;\n#define glClipPlane glad_glClipPlane\ntypedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode);\nGLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial;\n#define glColorMaterial glad_glColorMaterial\ntypedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param);\nGLAPI PFNGLFOGFPROC glad_glFogf;\n#define glFogf glad_glFogf\ntypedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat *params);\nGLAPI PFNGLFOGFVPROC glad_glFogfv;\n#define glFogfv glad_glFogfv\ntypedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param);\nGLAPI PFNGLFOGIPROC glad_glFogi;\n#define glFogi glad_glFogi\ntypedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint *params);\nGLAPI PFNGLFOGIVPROC glad_glFogiv;\n#define glFogiv glad_glFogiv\ntypedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param);\nGLAPI PFNGLLIGHTFPROC glad_glLightf;\n#define glLightf glad_glLightf\ntypedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat *params);\nGLAPI PFNGLLIGHTFVPROC glad_glLightfv;\n#define glLightfv glad_glLightfv\ntypedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param);\nGLAPI PFNGLLIGHTIPROC glad_glLighti;\n#define glLighti glad_glLighti\ntypedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint *params);\nGLAPI PFNGLLIGHTIVPROC glad_glLightiv;\n#define glLightiv glad_glLightiv\ntypedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param);\nGLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf;\n#define glLightModelf glad_glLightModelf\ntypedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat *params);\nGLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv;\n#define glLightModelfv glad_glLightModelfv\ntypedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param);\nGLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli;\n#define glLightModeli glad_glLightModeli\ntypedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint *params);\nGLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv;\n#define glLightModeliv glad_glLightModeliv\ntypedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern);\nGLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple;\n#define glLineStipple glad_glLineStipple\ntypedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param);\nGLAPI PFNGLMATERIALFPROC glad_glMaterialf;\n#define glMaterialf glad_glMaterialf\ntypedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat *params);\nGLAPI PFNGLMATERIALFVPROC glad_glMaterialfv;\n#define glMaterialfv glad_glMaterialfv\ntypedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param);\nGLAPI PFNGLMATERIALIPROC glad_glMateriali;\n#define glMateriali glad_glMateriali\ntypedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint *params);\nGLAPI PFNGLMATERIALIVPROC glad_glMaterialiv;\n#define glMaterialiv glad_glMaterialiv\ntypedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte *mask);\nGLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple;\n#define glPolygonStipple glad_glPolygonStipple\ntypedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode);\nGLAPI PFNGLSHADEMODELPROC glad_glShadeModel;\n#define glShadeModel glad_glShadeModel\ntypedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param);\nGLAPI PFNGLTEXENVFPROC glad_glTexEnvf;\n#define glTexEnvf glad_glTexEnvf\ntypedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat *params);\nGLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv;\n#define glTexEnvfv glad_glTexEnvfv\ntypedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param);\nGLAPI PFNGLTEXENVIPROC glad_glTexEnvi;\n#define glTexEnvi glad_glTexEnvi\ntypedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint *params);\nGLAPI PFNGLTEXENVIVPROC glad_glTexEnviv;\n#define glTexEnviv glad_glTexEnviv\ntypedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param);\nGLAPI PFNGLTEXGENDPROC glad_glTexGend;\n#define glTexGend glad_glTexGend\ntypedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble *params);\nGLAPI PFNGLTEXGENDVPROC glad_glTexGendv;\n#define glTexGendv glad_glTexGendv\ntypedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param);\nGLAPI PFNGLTEXGENFPROC glad_glTexGenf;\n#define glTexGenf glad_glTexGenf\ntypedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat *params);\nGLAPI PFNGLTEXGENFVPROC glad_glTexGenfv;\n#define glTexGenfv glad_glTexGenfv\ntypedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param);\nGLAPI PFNGLTEXGENIPROC glad_glTexGeni;\n#define glTexGeni glad_glTexGeni\ntypedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint *params);\nGLAPI PFNGLTEXGENIVPROC glad_glTexGeniv;\n#define glTexGeniv glad_glTexGeniv\ntypedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat *buffer);\nGLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer;\n#define glFeedbackBuffer glad_glFeedbackBuffer\ntypedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint *buffer);\nGLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer;\n#define glSelectBuffer glad_glSelectBuffer\ntypedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode);\nGLAPI PFNGLRENDERMODEPROC glad_glRenderMode;\n#define glRenderMode glad_glRenderMode\ntypedef void (APIENTRYP PFNGLINITNAMESPROC)(void);\nGLAPI PFNGLINITNAMESPROC glad_glInitNames;\n#define glInitNames glad_glInitNames\ntypedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name);\nGLAPI PFNGLLOADNAMEPROC glad_glLoadName;\n#define glLoadName glad_glLoadName\ntypedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token);\nGLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough;\n#define glPassThrough glad_glPassThrough\ntypedef void (APIENTRYP PFNGLPOPNAMEPROC)(void);\nGLAPI PFNGLPOPNAMEPROC glad_glPopName;\n#define glPopName glad_glPopName\ntypedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name);\nGLAPI PFNGLPUSHNAMEPROC glad_glPushName;\n#define glPushName glad_glPushName\ntypedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI PFNGLCLEARACCUMPROC glad_glClearAccum;\n#define glClearAccum glad_glClearAccum\ntypedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c);\nGLAPI PFNGLCLEARINDEXPROC glad_glClearIndex;\n#define glClearIndex glad_glClearIndex\ntypedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask);\nGLAPI PFNGLINDEXMASKPROC glad_glIndexMask;\n#define glIndexMask glad_glIndexMask\ntypedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value);\nGLAPI PFNGLACCUMPROC glad_glAccum;\n#define glAccum glad_glAccum\ntypedef void (APIENTRYP PFNGLPOPATTRIBPROC)(void);\nGLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib;\n#define glPopAttrib glad_glPopAttrib\ntypedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask);\nGLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib;\n#define glPushAttrib glad_glPushAttrib\ntypedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);\nGLAPI PFNGLMAP1DPROC glad_glMap1d;\n#define glMap1d glad_glMap1d\ntypedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);\nGLAPI PFNGLMAP1FPROC glad_glMap1f;\n#define glMap1f glad_glMap1f\ntypedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);\nGLAPI PFNGLMAP2DPROC glad_glMap2d;\n#define glMap2d glad_glMap2d\ntypedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);\nGLAPI PFNGLMAP2FPROC glad_glMap2f;\n#define glMap2f glad_glMap2f\ntypedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2);\nGLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d;\n#define glMapGrid1d glad_glMapGrid1d\ntypedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2);\nGLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f;\n#define glMapGrid1f glad_glMapGrid1f\ntypedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);\nGLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d;\n#define glMapGrid2d glad_glMapGrid2d\ntypedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);\nGLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f;\n#define glMapGrid2f glad_glMapGrid2f\ntypedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u);\nGLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d;\n#define glEvalCoord1d glad_glEvalCoord1d\ntypedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble *u);\nGLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv;\n#define glEvalCoord1dv glad_glEvalCoord1dv\ntypedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u);\nGLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f;\n#define glEvalCoord1f glad_glEvalCoord1f\ntypedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat *u);\nGLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv;\n#define glEvalCoord1fv glad_glEvalCoord1fv\ntypedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v);\nGLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d;\n#define glEvalCoord2d glad_glEvalCoord2d\ntypedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble *u);\nGLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv;\n#define glEvalCoord2dv glad_glEvalCoord2dv\ntypedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v);\nGLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f;\n#define glEvalCoord2f glad_glEvalCoord2f\ntypedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat *u);\nGLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv;\n#define glEvalCoord2fv glad_glEvalCoord2fv\ntypedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2);\nGLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1;\n#define glEvalMesh1 glad_glEvalMesh1\ntypedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i);\nGLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1;\n#define glEvalPoint1 glad_glEvalPoint1\ntypedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);\nGLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2;\n#define glEvalMesh2 glad_glEvalMesh2\ntypedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j);\nGLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2;\n#define glEvalPoint2 glad_glEvalPoint2\ntypedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref);\nGLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc;\n#define glAlphaFunc glad_glAlphaFunc\ntypedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor);\nGLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom;\n#define glPixelZoom glad_glPixelZoom\ntypedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param);\nGLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf;\n#define glPixelTransferf glad_glPixelTransferf\ntypedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param);\nGLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi;\n#define glPixelTransferi glad_glPixelTransferi\ntypedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat *values);\nGLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv;\n#define glPixelMapfv glad_glPixelMapfv\ntypedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint *values);\nGLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv;\n#define glPixelMapuiv glad_glPixelMapuiv\ntypedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort *values);\nGLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv;\n#define glPixelMapusv glad_glPixelMapusv\ntypedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);\nGLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels;\n#define glCopyPixels glad_glCopyPixels\ntypedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels;\n#define glDrawPixels glad_glDrawPixels\ntypedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble *equation);\nGLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane;\n#define glGetClipPlane glad_glGetClipPlane\ntypedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv;\n#define glGetLightfv glad_glGetLightfv\ntypedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint *params);\nGLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv;\n#define glGetLightiv glad_glGetLightiv\ntypedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble *v);\nGLAPI PFNGLGETMAPDVPROC glad_glGetMapdv;\n#define glGetMapdv glad_glGetMapdv\ntypedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat *v);\nGLAPI PFNGLGETMAPFVPROC glad_glGetMapfv;\n#define glGetMapfv glad_glGetMapfv\ntypedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint *v);\nGLAPI PFNGLGETMAPIVPROC glad_glGetMapiv;\n#define glGetMapiv glad_glGetMapiv\ntypedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv;\n#define glGetMaterialfv glad_glGetMaterialfv\ntypedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint *params);\nGLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv;\n#define glGetMaterialiv glad_glGetMaterialiv\ntypedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat *values);\nGLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv;\n#define glGetPixelMapfv glad_glGetPixelMapfv\ntypedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint *values);\nGLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv;\n#define glGetPixelMapuiv glad_glGetPixelMapuiv\ntypedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort *values);\nGLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv;\n#define glGetPixelMapusv glad_glGetPixelMapusv\ntypedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte *mask);\nGLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple;\n#define glGetPolygonStipple glad_glGetPolygonStipple\ntypedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv;\n#define glGetTexEnvfv glad_glGetTexEnvfv\ntypedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv;\n#define glGetTexEnviv glad_glGetTexEnviv\ntypedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble *params);\nGLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv;\n#define glGetTexGendv glad_glGetTexGendv\ntypedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv;\n#define glGetTexGenfv glad_glGetTexGenfv\ntypedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv;\n#define glGetTexGeniv glad_glGetTexGeniv\ntypedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list);\nGLAPI PFNGLISLISTPROC glad_glIsList;\n#define glIsList glad_glIsList\ntypedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI PFNGLFRUSTUMPROC glad_glFrustum;\n#define glFrustum glad_glFrustum\ntypedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(void);\nGLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity;\n#define glLoadIdentity glad_glLoadIdentity\ntypedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat *m);\nGLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf;\n#define glLoadMatrixf glad_glLoadMatrixf\ntypedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble *m);\nGLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd;\n#define glLoadMatrixd glad_glLoadMatrixd\ntypedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode);\nGLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode;\n#define glMatrixMode glad_glMatrixMode\ntypedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat *m);\nGLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf;\n#define glMultMatrixf glad_glMultMatrixf\ntypedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble *m);\nGLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd;\n#define glMultMatrixd glad_glMultMatrixd\ntypedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI PFNGLORTHOPROC glad_glOrtho;\n#define glOrtho glad_glOrtho\ntypedef void (APIENTRYP PFNGLPOPMATRIXPROC)(void);\nGLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix;\n#define glPopMatrix glad_glPopMatrix\ntypedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(void);\nGLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix;\n#define glPushMatrix glad_glPushMatrix\ntypedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLROTATEDPROC glad_glRotated;\n#define glRotated glad_glRotated\ntypedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLROTATEFPROC glad_glRotatef;\n#define glRotatef glad_glRotatef\ntypedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLSCALEDPROC glad_glScaled;\n#define glScaled glad_glScaled\ntypedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLSCALEFPROC glad_glScalef;\n#define glScalef glad_glScalef\ntypedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLTRANSLATEDPROC glad_glTranslated;\n#define glTranslated glad_glTranslated\ntypedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLTRANSLATEFPROC glad_glTranslatef;\n#define glTranslatef glad_glTranslatef\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 PFNGLGETPOINTERVPROC)(GLenum pname, void **params);\nGLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv;\n#define glGetPointerv glad_glGetPointerv\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\ntypedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i);\nGLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement;\n#define glArrayElement glad_glArrayElement\ntypedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer;\n#define glColorPointer glad_glColorPointer\ntypedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array);\nGLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState;\n#define glDisableClientState glad_glDisableClientState\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void *pointer);\nGLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer;\n#define glEdgeFlagPointer glad_glEdgeFlagPointer\ntypedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array);\nGLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState;\n#define glEnableClientState glad_glEnableClientState\ntypedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer;\n#define glIndexPointer glad_glIndexPointer\ntypedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void *pointer);\nGLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays;\n#define glInterleavedArrays glad_glInterleavedArrays\ntypedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer;\n#define glNormalPointer glad_glNormalPointer\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer;\n#define glTexCoordPointer glad_glTexCoordPointer\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer;\n#define glVertexPointer glad_glVertexPointer\ntypedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint *textures, GLboolean *residences);\nGLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident;\n#define glAreTexturesResident glad_glAreTexturesResident\ntypedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint *textures, const GLfloat *priorities);\nGLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures;\n#define glPrioritizeTextures glad_glPrioritizeTextures\ntypedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c);\nGLAPI PFNGLINDEXUBPROC glad_glIndexub;\n#define glIndexub glad_glIndexub\ntypedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte *c);\nGLAPI PFNGLINDEXUBVPROC glad_glIndexubv;\n#define glIndexubv glad_glIndexubv\ntypedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(void);\nGLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib;\n#define glPopClientAttrib glad_glPopClientAttrib\ntypedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask);\nGLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib;\n#define glPushClientAttrib glad_glPushClientAttrib\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\ntypedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture);\nGLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture;\n#define glClientActiveTexture glad_glClientActiveTexture\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s);\nGLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d;\n#define glMultiTexCoord1d glad_glMultiTexCoord1d\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble *v);\nGLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv;\n#define glMultiTexCoord1dv glad_glMultiTexCoord1dv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s);\nGLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f;\n#define glMultiTexCoord1f glad_glMultiTexCoord1f\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat *v);\nGLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv;\n#define glMultiTexCoord1fv glad_glMultiTexCoord1fv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s);\nGLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i;\n#define glMultiTexCoord1i glad_glMultiTexCoord1i\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint *v);\nGLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv;\n#define glMultiTexCoord1iv glad_glMultiTexCoord1iv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s);\nGLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s;\n#define glMultiTexCoord1s glad_glMultiTexCoord1s\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort *v);\nGLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv;\n#define glMultiTexCoord1sv glad_glMultiTexCoord1sv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t);\nGLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d;\n#define glMultiTexCoord2d glad_glMultiTexCoord2d\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble *v);\nGLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv;\n#define glMultiTexCoord2dv glad_glMultiTexCoord2dv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t);\nGLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f;\n#define glMultiTexCoord2f glad_glMultiTexCoord2f\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat *v);\nGLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv;\n#define glMultiTexCoord2fv glad_glMultiTexCoord2fv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t);\nGLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i;\n#define glMultiTexCoord2i glad_glMultiTexCoord2i\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint *v);\nGLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv;\n#define glMultiTexCoord2iv glad_glMultiTexCoord2iv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t);\nGLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s;\n#define glMultiTexCoord2s glad_glMultiTexCoord2s\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort *v);\nGLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv;\n#define glMultiTexCoord2sv glad_glMultiTexCoord2sv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r);\nGLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d;\n#define glMultiTexCoord3d glad_glMultiTexCoord3d\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble *v);\nGLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv;\n#define glMultiTexCoord3dv glad_glMultiTexCoord3dv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r);\nGLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f;\n#define glMultiTexCoord3f glad_glMultiTexCoord3f\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat *v);\nGLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv;\n#define glMultiTexCoord3fv glad_glMultiTexCoord3fv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r);\nGLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i;\n#define glMultiTexCoord3i glad_glMultiTexCoord3i\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint *v);\nGLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv;\n#define glMultiTexCoord3iv glad_glMultiTexCoord3iv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r);\nGLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s;\n#define glMultiTexCoord3s glad_glMultiTexCoord3s\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort *v);\nGLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv;\n#define glMultiTexCoord3sv glad_glMultiTexCoord3sv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\nGLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d;\n#define glMultiTexCoord4d glad_glMultiTexCoord4d\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble *v);\nGLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv;\n#define glMultiTexCoord4dv glad_glMultiTexCoord4dv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\nGLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f;\n#define glMultiTexCoord4f glad_glMultiTexCoord4f\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat *v);\nGLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv;\n#define glMultiTexCoord4fv glad_glMultiTexCoord4fv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q);\nGLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i;\n#define glMultiTexCoord4i glad_glMultiTexCoord4i\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint *v);\nGLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv;\n#define glMultiTexCoord4iv glad_glMultiTexCoord4iv\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\nGLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s;\n#define glMultiTexCoord4s glad_glMultiTexCoord4s\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort *v);\nGLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv;\n#define glMultiTexCoord4sv glad_glMultiTexCoord4sv\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat *m);\nGLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf;\n#define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble *m);\nGLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd;\n#define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat *m);\nGLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf;\n#define glMultTransposeMatrixf glad_glMultTransposeMatrixf\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble *m);\nGLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd;\n#define glMultTransposeMatrixd glad_glMultTransposeMatrixd\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 PFNGLFOGCOORDFPROC)(GLfloat coord);\nGLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf;\n#define glFogCoordf glad_glFogCoordf\ntypedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat *coord);\nGLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv;\n#define glFogCoordfv glad_glFogCoordfv\ntypedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord);\nGLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd;\n#define glFogCoordd glad_glFogCoordd\ntypedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble *coord);\nGLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv;\n#define glFogCoorddv glad_glFogCoorddv\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer;\n#define glFogCoordPointer glad_glFogCoordPointer\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue);\nGLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b;\n#define glSecondaryColor3b glad_glSecondaryColor3b\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte *v);\nGLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv;\n#define glSecondaryColor3bv glad_glSecondaryColor3bv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue);\nGLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d;\n#define glSecondaryColor3d glad_glSecondaryColor3d\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble *v);\nGLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv;\n#define glSecondaryColor3dv glad_glSecondaryColor3dv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue);\nGLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f;\n#define glSecondaryColor3f glad_glSecondaryColor3f\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat *v);\nGLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv;\n#define glSecondaryColor3fv glad_glSecondaryColor3fv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue);\nGLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i;\n#define glSecondaryColor3i glad_glSecondaryColor3i\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint *v);\nGLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv;\n#define glSecondaryColor3iv glad_glSecondaryColor3iv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue);\nGLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s;\n#define glSecondaryColor3s glad_glSecondaryColor3s\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort *v);\nGLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv;\n#define glSecondaryColor3sv glad_glSecondaryColor3sv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue);\nGLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub;\n#define glSecondaryColor3ub glad_glSecondaryColor3ub\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte *v);\nGLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv;\n#define glSecondaryColor3ubv glad_glSecondaryColor3ubv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue);\nGLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui;\n#define glSecondaryColor3ui glad_glSecondaryColor3ui\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint *v);\nGLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv;\n#define glSecondaryColor3uiv glad_glSecondaryColor3uiv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue);\nGLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us;\n#define glSecondaryColor3us glad_glSecondaryColor3us\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort *v);\nGLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv;\n#define glSecondaryColor3usv glad_glSecondaryColor3usv\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer;\n#define glSecondaryColorPointer glad_glSecondaryColorPointer\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y);\nGLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d;\n#define glWindowPos2d glad_glWindowPos2d\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble *v);\nGLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv;\n#define glWindowPos2dv glad_glWindowPos2dv\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y);\nGLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f;\n#define glWindowPos2f glad_glWindowPos2f\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat *v);\nGLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv;\n#define glWindowPos2fv glad_glWindowPos2fv\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y);\nGLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i;\n#define glWindowPos2i glad_glWindowPos2i\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint *v);\nGLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv;\n#define glWindowPos2iv glad_glWindowPos2iv\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y);\nGLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s;\n#define glWindowPos2s glad_glWindowPos2s\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort *v);\nGLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv;\n#define glWindowPos2sv glad_glWindowPos2sv\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d;\n#define glWindowPos3d glad_glWindowPos3d\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble *v);\nGLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv;\n#define glWindowPos3dv glad_glWindowPos3dv\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z);\nGLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f;\n#define glWindowPos3f glad_glWindowPos3f\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat *v);\nGLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv;\n#define glWindowPos3fv glad_glWindowPos3fv\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z);\nGLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i;\n#define glWindowPos3i glad_glWindowPos3i\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint *v);\nGLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv;\n#define glWindowPos3iv glad_glWindowPos3iv\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z);\nGLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s;\n#define glWindowPos3s glad_glWindowPos3s\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort *v);\nGLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv;\n#define glWindowPos3sv glad_glWindowPos3sv\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#ifndef GL_VERSION_4_0\n#define GL_VERSION_4_0 1\nGLAPI int GLAD_GL_VERSION_4_0;\ntypedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value);\nGLAPI PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;\n#define glMinSampleShading glad_glMinSampleShading\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode);\nGLAPI PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;\n#define glBlendEquationi glad_glBlendEquationi\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);\nGLAPI PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;\n#define glBlendEquationSeparatei glad_glBlendEquationSeparatei\ntypedef void (APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst);\nGLAPI PFNGLBLENDFUNCIPROC glad_glBlendFunci;\n#define glBlendFunci glad_glBlendFunci\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\nGLAPI PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;\n#define glBlendFuncSeparatei glad_glBlendFuncSeparatei\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect);\nGLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;\n#define glDrawArraysIndirect glad_glDrawArraysIndirect\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect);\nGLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;\n#define glDrawElementsIndirect glad_glDrawElementsIndirect\ntypedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x);\nGLAPI PFNGLUNIFORM1DPROC glad_glUniform1d;\n#define glUniform1d glad_glUniform1d\ntypedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y);\nGLAPI PFNGLUNIFORM2DPROC glad_glUniform2d;\n#define glUniform2d glad_glUniform2d\ntypedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLUNIFORM3DPROC glad_glUniform3d;\n#define glUniform3d glad_glUniform3d\ntypedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI PFNGLUNIFORM4DPROC glad_glUniform4d;\n#define glUniform4d glad_glUniform4d\ntypedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv;\n#define glUniform1dv glad_glUniform1dv\ntypedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv;\n#define glUniform2dv glad_glUniform2dv\ntypedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv;\n#define glUniform3dv glad_glUniform3dv\ntypedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv;\n#define glUniform4dv glad_glUniform4dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;\n#define glUniformMatrix2dv glad_glUniformMatrix2dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;\n#define glUniformMatrix3dv glad_glUniformMatrix3dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;\n#define glUniformMatrix4dv glad_glUniformMatrix4dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;\n#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;\n#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;\n#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;\n#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;\n#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;\n#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv\ntypedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params);\nGLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;\n#define glGetUniformdv glad_glGetUniformdv\ntypedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name);\nGLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;\n#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation\ntypedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name);\nGLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;\n#define glGetSubroutineIndex glad_glGetSubroutineIndex\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);\nGLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;\n#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;\n#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;\n#define glGetActiveSubroutineName glad_glGetActiveSubroutineName\ntypedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices);\nGLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;\n#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv\ntypedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params);\nGLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;\n#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values);\nGLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;\n#define glGetProgramStageiv glad_glGetProgramStageiv\ntypedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);\nGLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;\n#define glPatchParameteri glad_glPatchParameteri\ntypedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values);\nGLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;\n#define glPatchParameterfv glad_glPatchParameterfv\ntypedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);\nGLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;\n#define glBindTransformFeedback glad_glBindTransformFeedback\ntypedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids);\nGLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;\n#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks\ntypedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);\nGLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;\n#define glGenTransformFeedbacks glad_glGenTransformFeedbacks\ntypedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);\nGLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;\n#define glIsTransformFeedback glad_glIsTransformFeedback\ntypedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);\nGLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;\n#define glPauseTransformFeedback glad_glPauseTransformFeedback\ntypedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);\nGLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;\n#define glResumeTransformFeedback glad_glResumeTransformFeedback\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id);\nGLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;\n#define glDrawTransformFeedback glad_glDrawTransformFeedback\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream);\nGLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;\n#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream\ntypedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id);\nGLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;\n#define glBeginQueryIndexed glad_glBeginQueryIndexed\ntypedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index);\nGLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;\n#define glEndQueryIndexed glad_glEndQueryIndexed\ntypedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params);\nGLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;\n#define glGetQueryIndexediv glad_glGetQueryIndexediv\n#endif\n#ifndef GL_VERSION_4_1\n#define GL_VERSION_4_1 1\nGLAPI int GLAD_GL_VERSION_4_1;\ntypedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void);\nGLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;\n#define glReleaseShaderCompiler glad_glReleaseShaderCompiler\ntypedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length);\nGLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary;\n#define glShaderBinary glad_glShaderBinary\ntypedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);\nGLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;\n#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat\ntypedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);\nGLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef;\n#define glDepthRangef glad_glDepthRangef\ntypedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d);\nGLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf;\n#define glClearDepthf glad_glClearDepthf\ntypedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\nGLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;\n#define glGetProgramBinary glad_glGetProgramBinary\ntypedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);\nGLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary;\n#define glProgramBinary glad_glProgramBinary\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value);\nGLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;\n#define glProgramParameteri glad_glProgramParameteri\ntypedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);\nGLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;\n#define glUseProgramStages glad_glUseProgramStages\ntypedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);\nGLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;\n#define glActiveShaderProgram glad_glActiveShaderProgram\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings);\nGLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;\n#define glCreateShaderProgramv glad_glCreateShaderProgramv\ntypedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);\nGLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;\n#define glBindProgramPipeline glad_glBindProgramPipeline\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines);\nGLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;\n#define glDeleteProgramPipelines glad_glDeleteProgramPipelines\ntypedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines);\nGLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;\n#define glGenProgramPipelines glad_glGenProgramPipelines\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);\nGLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;\n#define glIsProgramPipeline glad_glIsProgramPipeline\ntypedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params);\nGLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;\n#define glGetProgramPipelineiv glad_glGetProgramPipelineiv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);\nGLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;\n#define glProgramUniform1i glad_glProgramUniform1i\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;\n#define glProgramUniform1iv glad_glProgramUniform1iv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);\nGLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;\n#define glProgramUniform1f glad_glProgramUniform1f\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;\n#define glProgramUniform1fv glad_glProgramUniform1fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0);\nGLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;\n#define glProgramUniform1d glad_glProgramUniform1d\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;\n#define glProgramUniform1dv glad_glProgramUniform1dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);\nGLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;\n#define glProgramUniform1ui glad_glProgramUniform1ui\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;\n#define glProgramUniform1uiv glad_glProgramUniform1uiv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);\nGLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;\n#define glProgramUniform2i glad_glProgramUniform2i\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;\n#define glProgramUniform2iv glad_glProgramUniform2iv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);\nGLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;\n#define glProgramUniform2f glad_glProgramUniform2f\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;\n#define glProgramUniform2fv glad_glProgramUniform2fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1);\nGLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;\n#define glProgramUniform2d glad_glProgramUniform2d\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;\n#define glProgramUniform2dv glad_glProgramUniform2dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);\nGLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;\n#define glProgramUniform2ui glad_glProgramUniform2ui\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;\n#define glProgramUniform2uiv glad_glProgramUniform2uiv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;\n#define glProgramUniform3i glad_glProgramUniform3i\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;\n#define glProgramUniform3iv glad_glProgramUniform3iv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;\n#define glProgramUniform3f glad_glProgramUniform3f\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;\n#define glProgramUniform3fv glad_glProgramUniform3fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);\nGLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;\n#define glProgramUniform3d glad_glProgramUniform3d\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;\n#define glProgramUniform3dv glad_glProgramUniform3dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;\n#define glProgramUniform3ui glad_glProgramUniform3ui\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;\n#define glProgramUniform3uiv glad_glProgramUniform3uiv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;\n#define glProgramUniform4i glad_glProgramUniform4i\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;\n#define glProgramUniform4iv glad_glProgramUniform4iv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;\n#define glProgramUniform4f glad_glProgramUniform4f\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;\n#define glProgramUniform4fv glad_glProgramUniform4fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);\nGLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;\n#define glProgramUniform4d glad_glProgramUniform4d\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;\n#define glProgramUniform4dv glad_glProgramUniform4dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;\n#define glProgramUniform4ui glad_glProgramUniform4ui\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;\n#define glProgramUniform4uiv glad_glProgramUniform4uiv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;\n#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;\n#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;\n#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;\n#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;\n#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;\n#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;\n#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;\n#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;\n#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;\n#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;\n#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;\n#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;\n#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;\n#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;\n#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;\n#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;\n#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;\n#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);\nGLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;\n#define glValidateProgramPipeline glad_glValidateProgramPipeline\ntypedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;\n#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x);\nGLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;\n#define glVertexAttribL1d glad_glVertexAttribL1d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y);\nGLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;\n#define glVertexAttribL2d glad_glVertexAttribL2d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;\n#define glVertexAttribL3d glad_glVertexAttribL3d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;\n#define glVertexAttribL4d glad_glVertexAttribL4d\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;\n#define glVertexAttribL1dv glad_glVertexAttribL1dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;\n#define glVertexAttribL2dv glad_glVertexAttribL2dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;\n#define glVertexAttribL3dv glad_glVertexAttribL3dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v);\nGLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;\n#define glVertexAttribL4dv glad_glVertexAttribL4dv\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;\n#define glVertexAttribLPointer glad_glVertexAttribLPointer\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params);\nGLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;\n#define glGetVertexAttribLdv glad_glGetVertexAttribLdv\ntypedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v);\nGLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;\n#define glViewportArrayv glad_glViewportArrayv\ntypedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\nGLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;\n#define glViewportIndexedf glad_glViewportIndexedf\ntypedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v);\nGLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;\n#define glViewportIndexedfv glad_glViewportIndexedfv\ntypedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v);\nGLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;\n#define glScissorArrayv glad_glScissorArrayv\ntypedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\nGLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;\n#define glScissorIndexed glad_glScissorIndexed\ntypedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v);\nGLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;\n#define glScissorIndexedv glad_glScissorIndexedv\ntypedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v);\nGLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;\n#define glDepthRangeArrayv glad_glDepthRangeArrayv\ntypedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);\nGLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;\n#define glDepthRangeIndexed glad_glDepthRangeIndexed\ntypedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data);\nGLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v;\n#define glGetFloati_v glad_glGetFloati_v\ntypedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data);\nGLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;\n#define glGetDoublei_v glad_glGetDoublei_v\n#endif\n#ifndef GL_VERSION_4_2\n#define GL_VERSION_4_2 1\nGLAPI int GLAD_GL_VERSION_4_2;\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\nGLAPI PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;\n#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\nGLAPI PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;\n#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\nGLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;\n#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance\ntypedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params);\nGLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;\n#define glGetInternalformativ glad_glGetInternalformativ\ntypedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);\nGLAPI PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;\n#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv\ntypedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);\nGLAPI PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;\n#define glBindImageTexture glad_glBindImageTexture\ntypedef void (APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers);\nGLAPI PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;\n#define glMemoryBarrier glad_glMemoryBarrier\ntypedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;\n#define glTexStorage1D glad_glTexStorage1D\ntypedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;\n#define glTexStorage2D glad_glTexStorage2D\ntypedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;\n#define glTexStorage3D glad_glTexStorage3D\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount);\nGLAPI PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;\n#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);\nGLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;\n#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced\n#endif\n#ifndef GL_VERSION_4_3\n#define GL_VERSION_4_3 1\nGLAPI int GLAD_GL_VERSION_4_3;\ntypedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;\n#define glClearBufferData glad_glClearBufferData\ntypedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;\n#define glClearBufferSubData glad_glClearBufferSubData\ntypedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);\nGLAPI PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;\n#define glDispatchCompute glad_glDispatchCompute\ntypedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);\nGLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;\n#define glDispatchComputeIndirect glad_glDispatchComputeIndirect\ntypedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);\nGLAPI PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;\n#define glCopyImageSubData glad_glCopyImageSubData\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);\nGLAPI PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;\n#define glFramebufferParameteri glad_glFramebufferParameteri\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params);\nGLAPI PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;\n#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv\ntypedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params);\nGLAPI PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;\n#define glGetInternalformati64v glad_glGetInternalformati64v\ntypedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;\n#define glInvalidateTexSubImage glad_glInvalidateTexSubImage\ntypedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level);\nGLAPI PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;\n#define glInvalidateTexImage glad_glInvalidateTexImage\ntypedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length);\nGLAPI PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;\n#define glInvalidateBufferSubData glad_glInvalidateBufferSubData\ntypedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer);\nGLAPI PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;\n#define glInvalidateBufferData glad_glInvalidateBufferData\ntypedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments);\nGLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;\n#define glInvalidateFramebuffer glad_glInvalidateFramebuffer\ntypedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;\n#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\nGLAPI PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;\n#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\nGLAPI PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;\n#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect\ntypedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint *params);\nGLAPI PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;\n#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv\ntypedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;\n#define glGetProgramResourceIndex glad_glGetProgramResourceIndex\ntypedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;\n#define glGetProgramResourceName glad_glGetProgramResourceName\ntypedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params);\nGLAPI PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;\n#define glGetProgramResourceiv glad_glGetProgramResourceiv\ntypedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;\n#define glGetProgramResourceLocation glad_glGetProgramResourceLocation\ntypedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;\n#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex\ntypedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);\nGLAPI PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;\n#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding\ntypedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;\n#define glTexBufferRange glad_glTexBufferRange\ntypedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;\n#define glTexStorage2DMultisample glad_glTexStorage2DMultisample\ntypedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;\n#define glTexStorage3DMultisample glad_glTexStorage3DMultisample\ntypedef void (APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\nGLAPI PFNGLTEXTUREVIEWPROC glad_glTextureView;\n#define glTextureView glad_glTextureView\ntypedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\nGLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;\n#define glBindVertexBuffer glad_glBindVertexBuffer\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\nGLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;\n#define glVertexAttribFormat glad_glVertexAttribFormat\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;\n#define glVertexAttribIFormat glad_glVertexAttribIFormat\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;\n#define glVertexAttribLFormat glad_glVertexAttribLFormat\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);\nGLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;\n#define glVertexAttribBinding glad_glVertexAttribBinding\ntypedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);\nGLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;\n#define glVertexBindingDivisor glad_glVertexBindingDivisor\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\nGLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;\n#define glDebugMessageControl glad_glDebugMessageControl\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\nGLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;\n#define glDebugMessageInsert glad_glDebugMessageInsert\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam);\nGLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;\n#define glDebugMessageCallback glad_glDebugMessageCallback\ntypedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\nGLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;\n#define glGetDebugMessageLog glad_glGetDebugMessageLog\ntypedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message);\nGLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;\n#define glPushDebugGroup glad_glPushDebugGroup\ntypedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void);\nGLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;\n#define glPopDebugGroup glad_glPopDebugGroup\ntypedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\nGLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel;\n#define glObjectLabel glad_glObjectLabel\ntypedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\nGLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;\n#define glGetObjectLabel glad_glGetObjectLabel\ntypedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label);\nGLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;\n#define glObjectPtrLabel glad_glObjectPtrLabel\ntypedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\nGLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;\n#define glGetObjectPtrLabel glad_glGetObjectPtrLabel\n#endif\n#ifndef GL_VERSION_4_4\n#define GL_VERSION_4_4 1\nGLAPI int GLAD_GL_VERSION_4_4;\ntypedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\nGLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;\n#define glBufferStorage glad_glBufferStorage\ntypedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage;\n#define glClearTexImage glad_glClearTexImage\ntypedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage;\n#define glClearTexSubImage glad_glClearTexSubImage\ntypedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers);\nGLAPI PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase;\n#define glBindBuffersBase glad_glBindBuffersBase\ntypedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);\nGLAPI PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange;\n#define glBindBuffersRange glad_glBindBuffersRange\ntypedef void (APIENTRYP PFNGLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures);\nGLAPI PFNGLBINDTEXTURESPROC glad_glBindTextures;\n#define glBindTextures glad_glBindTextures\ntypedef void (APIENTRYP PFNGLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint *samplers);\nGLAPI PFNGLBINDSAMPLERSPROC glad_glBindSamplers;\n#define glBindSamplers glad_glBindSamplers\ntypedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures);\nGLAPI PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures;\n#define glBindImageTextures glad_glBindImageTextures\ntypedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\nGLAPI PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;\n#define glBindVertexBuffers glad_glBindVertexBuffers\n#endif\n#ifndef GL_VERSION_4_5\n#define GL_VERSION_4_5 1\nGLAPI int GLAD_GL_VERSION_4_5;\ntypedef void (APIENTRYP PFNGLCLIPCONTROLPROC)(GLenum origin, GLenum depth);\nGLAPI PFNGLCLIPCONTROLPROC glad_glClipControl;\n#define glClipControl glad_glClipControl\ntypedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids);\nGLAPI PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks;\n#define glCreateTransformFeedbacks glad_glCreateTransformFeedbacks\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint xfb, GLuint index, GLuint buffer);\nGLAPI PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase;\n#define glTransformFeedbackBufferBase glad_glTransformFeedbackBufferBase\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange;\n#define glTransformFeedbackBufferRange glad_glTransformFeedbackBufferRange\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC)(GLuint xfb, GLenum pname, GLint *param);\nGLAPI PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv;\n#define glGetTransformFeedbackiv glad_glGetTransformFeedbackiv\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint *param);\nGLAPI PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v;\n#define glGetTransformFeedbacki_v glad_glGetTransformFeedbacki_v\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint64 *param);\nGLAPI PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v;\n#define glGetTransformFeedbacki64_v glad_glGetTransformFeedbacki64_v\ntypedef void (APIENTRYP PFNGLCREATEBUFFERSPROC)(GLsizei n, GLuint *buffers);\nGLAPI PFNGLCREATEBUFFERSPROC glad_glCreateBuffers;\n#define glCreateBuffers glad_glCreateBuffers\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC)(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);\nGLAPI PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage;\n#define glNamedBufferStorage glad_glNamedBufferStorage\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC)(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);\nGLAPI PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData;\n#define glNamedBufferData glad_glNamedBufferData\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData;\n#define glNamedBufferSubData glad_glNamedBufferSubData\ntypedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData;\n#define glCopyNamedBufferSubData glad_glCopyNamedBufferSubData\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC)(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData;\n#define glClearNamedBufferData glad_glClearNamedBufferData\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\nGLAPI PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData;\n#define glClearNamedBufferSubData glad_glClearNamedBufferSubData\ntypedef void * (APIENTRYP PFNGLMAPNAMEDBUFFERPROC)(GLuint buffer, GLenum access);\nGLAPI PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer;\n#define glMapNamedBuffer glad_glMapNamedBuffer\ntypedef void * (APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);\nGLAPI PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange;\n#define glMapNamedBufferRange glad_glMapNamedBufferRange\ntypedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC)(GLuint buffer);\nGLAPI PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer;\n#define glUnmapNamedBuffer glad_glUnmapNamedBuffer\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length);\nGLAPI PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange;\n#define glFlushMappedNamedBufferRange glad_glFlushMappedNamedBufferRange\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint buffer, GLenum pname, GLint *params);\nGLAPI PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv;\n#define glGetNamedBufferParameteriv glad_glGetNamedBufferParameteriv\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint buffer, GLenum pname, GLint64 *params);\nGLAPI PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v;\n#define glGetNamedBufferParameteri64v glad_glGetNamedBufferParameteri64v\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC)(GLuint buffer, GLenum pname, void **params);\nGLAPI PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv;\n#define glGetNamedBufferPointerv glad_glGetNamedBufferPointerv\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);\nGLAPI PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData;\n#define glGetNamedBufferSubData glad_glGetNamedBufferSubData\ntypedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers);\nGLAPI PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers;\n#define glCreateFramebuffers glad_glCreateFramebuffers\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer;\n#define glNamedFramebufferRenderbuffer glad_glNamedFramebufferRenderbuffer\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint framebuffer, GLenum pname, GLint param);\nGLAPI PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri;\n#define glNamedFramebufferParameteri glad_glNamedFramebufferParameteri\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);\nGLAPI PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture;\n#define glNamedFramebufferTexture glad_glNamedFramebufferTexture\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer;\n#define glNamedFramebufferTextureLayer glad_glNamedFramebufferTextureLayer\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint framebuffer, GLenum buf);\nGLAPI PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer;\n#define glNamedFramebufferDrawBuffer glad_glNamedFramebufferDrawBuffer\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint framebuffer, GLsizei n, const GLenum *bufs);\nGLAPI PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers;\n#define glNamedFramebufferDrawBuffers glad_glNamedFramebufferDrawBuffers\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint framebuffer, GLenum src);\nGLAPI PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer;\n#define glNamedFramebufferReadBuffer glad_glNamedFramebufferReadBuffer\ntypedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);\nGLAPI PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData;\n#define glInvalidateNamedFramebufferData glad_glInvalidateNamedFramebufferData\ntypedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData;\n#define glInvalidateNamedFramebufferSubData glad_glInvalidateNamedFramebufferSubData\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);\nGLAPI PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv;\n#define glClearNamedFramebufferiv glad_glClearNamedFramebufferiv\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);\nGLAPI PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv;\n#define glClearNamedFramebufferuiv glad_glClearNamedFramebufferuiv\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);\nGLAPI PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv;\n#define glClearNamedFramebufferfv glad_glClearNamedFramebufferfv\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\nGLAPI PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi;\n#define glClearNamedFramebufferfi glad_glClearNamedFramebufferfi\ntypedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC)(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\nGLAPI PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer;\n#define glBlitNamedFramebuffer glad_glBlitNamedFramebuffer\ntypedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint framebuffer, GLenum target);\nGLAPI PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus;\n#define glCheckNamedFramebufferStatus glad_glCheckNamedFramebufferStatus\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint framebuffer, GLenum pname, GLint *param);\nGLAPI PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv;\n#define glGetNamedFramebufferParameteriv glad_glGetNamedFramebufferParameteriv\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);\nGLAPI PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv;\n#define glGetNamedFramebufferAttachmentParameteriv glad_glGetNamedFramebufferAttachmentParameteriv\ntypedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers);\nGLAPI PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers;\n#define glCreateRenderbuffers glad_glCreateRenderbuffers\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage;\n#define glNamedRenderbufferStorage glad_glNamedRenderbufferStorage\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample;\n#define glNamedRenderbufferStorageMultisample glad_glNamedRenderbufferStorageMultisample\ntypedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint renderbuffer, GLenum pname, GLint *params);\nGLAPI PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv;\n#define glGetNamedRenderbufferParameteriv glad_glGetNamedRenderbufferParameteriv\ntypedef void (APIENTRYP PFNGLCREATETEXTURESPROC)(GLenum target, GLsizei n, GLuint *textures);\nGLAPI PFNGLCREATETEXTURESPROC glad_glCreateTextures;\n#define glCreateTextures glad_glCreateTextures\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC)(GLuint texture, GLenum internalformat, GLuint buffer);\nGLAPI PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer;\n#define glTextureBuffer glad_glTextureBuffer\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC)(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange;\n#define glTextureBufferRange glad_glTextureBufferRange\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D;\n#define glTextureStorage1D glad_glTextureStorage1D\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D;\n#define glTextureStorage2D glad_glTextureStorage2D\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D;\n#define glTextureStorage3D glad_glTextureStorage3D\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample;\n#define glTextureStorage2DMultisample glad_glTextureStorage2DMultisample\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample;\n#define glTextureStorage3DMultisample glad_glTextureStorage3DMultisample\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D;\n#define glTextureSubImage1D glad_glTextureSubImage1D\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D;\n#define glTextureSubImage2D glad_glTextureSubImage2D\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D;\n#define glTextureSubImage3D glad_glTextureSubImage3D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D;\n#define glCompressedTextureSubImage1D glad_glCompressedTextureSubImage1D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D;\n#define glCompressedTextureSubImage2D glad_glCompressedTextureSubImage2D\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\nGLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D;\n#define glCompressedTextureSubImage3D glad_glCompressedTextureSubImage3D\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D;\n#define glCopyTextureSubImage1D glad_glCopyTextureSubImage1D\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D;\n#define glCopyTextureSubImage2D glad_glCopyTextureSubImage2D\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D;\n#define glCopyTextureSubImage3D glad_glCopyTextureSubImage3D\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC)(GLuint texture, GLenum pname, GLfloat param);\nGLAPI PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf;\n#define glTextureParameterf glad_glTextureParameterf\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, const GLfloat *param);\nGLAPI PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv;\n#define glTextureParameterfv glad_glTextureParameterfv\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC)(GLuint texture, GLenum pname, GLint param);\nGLAPI PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri;\n#define glTextureParameteri glad_glTextureParameteri\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, const GLint *params);\nGLAPI PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv;\n#define glTextureParameterIiv glad_glTextureParameterIiv\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, const GLuint *params);\nGLAPI PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv;\n#define glTextureParameterIuiv glad_glTextureParameterIuiv\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, const GLint *param);\nGLAPI PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv;\n#define glTextureParameteriv glad_glTextureParameteriv\ntypedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC)(GLuint texture);\nGLAPI PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap;\n#define glGenerateTextureMipmap glad_glGenerateTextureMipmap\ntypedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC)(GLuint unit, GLuint texture);\nGLAPI PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit;\n#define glBindTextureUnit glad_glBindTextureUnit\ntypedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage;\n#define glGetTextureImage glad_glGetTextureImage\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage;\n#define glGetCompressedTextureImage glad_glGetCompressedTextureImage\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC)(GLuint texture, GLint level, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv;\n#define glGetTextureLevelParameterfv glad_glGetTextureLevelParameterfv\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC)(GLuint texture, GLint level, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv;\n#define glGetTextureLevelParameteriv glad_glGetTextureLevelParameteriv\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, GLfloat *params);\nGLAPI PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv;\n#define glGetTextureParameterfv glad_glGetTextureParameterfv\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv;\n#define glGetTextureParameterIiv glad_glGetTextureParameterIiv\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, GLuint *params);\nGLAPI PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv;\n#define glGetTextureParameterIuiv glad_glGetTextureParameterIuiv\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, GLint *params);\nGLAPI PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv;\n#define glGetTextureParameteriv glad_glGetTextureParameteriv\ntypedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays);\nGLAPI PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays;\n#define glCreateVertexArrays glad_glCreateVertexArrays\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index);\nGLAPI PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib;\n#define glDisableVertexArrayAttrib glad_glDisableVertexArrayAttrib\ntypedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index);\nGLAPI PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib;\n#define glEnableVertexArrayAttrib glad_glEnableVertexArrayAttrib\ntypedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC)(GLuint vaobj, GLuint buffer);\nGLAPI PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer;\n#define glVertexArrayElementBuffer glad_glVertexArrayElementBuffer\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC)(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\nGLAPI PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer;\n#define glVertexArrayVertexBuffer glad_glVertexArrayVertexBuffer\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\nGLAPI PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers;\n#define glVertexArrayVertexBuffers glad_glVertexArrayVertexBuffers\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC)(GLuint vaobj, GLuint attribindex, GLuint bindingindex);\nGLAPI PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding;\n#define glVertexArrayAttribBinding glad_glVertexArrayAttribBinding\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\nGLAPI PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat;\n#define glVertexArrayAttribFormat glad_glVertexArrayAttribFormat\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat;\n#define glVertexArrayAttribIFormat glad_glVertexArrayAttribIFormat\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat;\n#define glVertexArrayAttribLFormat glad_glVertexArrayAttribLFormat\ntypedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC)(GLuint vaobj, GLuint bindingindex, GLuint divisor);\nGLAPI PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor;\n#define glVertexArrayBindingDivisor glad_glVertexArrayBindingDivisor\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC)(GLuint vaobj, GLenum pname, GLint *param);\nGLAPI PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv;\n#define glGetVertexArrayiv glad_glGetVertexArrayiv\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint *param);\nGLAPI PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv;\n#define glGetVertexArrayIndexediv glad_glGetVertexArrayIndexediv\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);\nGLAPI PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv;\n#define glGetVertexArrayIndexed64iv glad_glGetVertexArrayIndexed64iv\ntypedef void (APIENTRYP PFNGLCREATESAMPLERSPROC)(GLsizei n, GLuint *samplers);\nGLAPI PFNGLCREATESAMPLERSPROC glad_glCreateSamplers;\n#define glCreateSamplers glad_glCreateSamplers\ntypedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines);\nGLAPI PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines;\n#define glCreateProgramPipelines glad_glCreateProgramPipelines\ntypedef void (APIENTRYP PFNGLCREATEQUERIESPROC)(GLenum target, GLsizei n, GLuint *ids);\nGLAPI PFNGLCREATEQUERIESPROC glad_glCreateQueries;\n#define glCreateQueries glad_glCreateQueries\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v;\n#define glGetQueryBufferObjecti64v glad_glGetQueryBufferObjecti64v\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv;\n#define glGetQueryBufferObjectiv glad_glGetQueryBufferObjectiv\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v;\n#define glGetQueryBufferObjectui64v glad_glGetQueryBufferObjectui64v\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv;\n#define glGetQueryBufferObjectuiv glad_glGetQueryBufferObjectuiv\ntypedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers);\nGLAPI PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;\n#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion\ntypedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage;\n#define glGetTextureSubImage glad_glGetTextureSubImage\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage;\n#define glGetCompressedTextureSubImage glad_glGetCompressedTextureSubImage\ntypedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC)(void);\nGLAPI PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;\n#define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus\ntypedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint lod, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage;\n#define glGetnCompressedTexImage glad_glGetnCompressedTexImage\ntypedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\nGLAPI PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage;\n#define glGetnTexImage glad_glGetnTexImage\ntypedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\nGLAPI PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv;\n#define glGetnUniformdv glad_glGetnUniformdv\ntypedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\nGLAPI PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;\n#define glGetnUniformfv glad_glGetnUniformfv\ntypedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params);\nGLAPI PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;\n#define glGetnUniformiv glad_glGetnUniformiv\ntypedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params);\nGLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;\n#define glGetnUniformuiv glad_glGetnUniformuiv\ntypedef void (APIENTRYP PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\nGLAPI PFNGLREADNPIXELSPROC glad_glReadnPixels;\n#define glReadnPixels glad_glReadnPixels\ntypedef void (APIENTRYP PFNGLGETNMAPDVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\nGLAPI PFNGLGETNMAPDVPROC glad_glGetnMapdv;\n#define glGetnMapdv glad_glGetnMapdv\ntypedef void (APIENTRYP PFNGLGETNMAPFVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\nGLAPI PFNGLGETNMAPFVPROC glad_glGetnMapfv;\n#define glGetnMapfv glad_glGetnMapfv\ntypedef void (APIENTRYP PFNGLGETNMAPIVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint *v);\nGLAPI PFNGLGETNMAPIVPROC glad_glGetnMapiv;\n#define glGetnMapiv glad_glGetnMapiv\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC)(GLenum map, GLsizei bufSize, GLfloat *values);\nGLAPI PFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv;\n#define glGetnPixelMapfv glad_glGetnPixelMapfv\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC)(GLenum map, GLsizei bufSize, GLuint *values);\nGLAPI PFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv;\n#define glGetnPixelMapuiv glad_glGetnPixelMapuiv\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC)(GLenum map, GLsizei bufSize, GLushort *values);\nGLAPI PFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv;\n#define glGetnPixelMapusv glad_glGetnPixelMapusv\ntypedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC)(GLsizei bufSize, GLubyte *pattern);\nGLAPI PFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple;\n#define glGetnPolygonStipple glad_glGetnPolygonStipple\ntypedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\nGLAPI PFNGLGETNCOLORTABLEPROC glad_glGetnColorTable;\n#define glGetnColorTable glad_glGetnColorTable\ntypedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\nGLAPI PFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter;\n#define glGetnConvolutionFilter glad_glGetnConvolutionFilter\ntypedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\nGLAPI PFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter;\n#define glGetnSeparableFilter glad_glGetnSeparableFilter\ntypedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\nGLAPI PFNGLGETNHISTOGRAMPROC glad_glGetnHistogram;\n#define glGetnHistogram glad_glGetnHistogram\ntypedef void (APIENTRYP PFNGLGETNMINMAXPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\nGLAPI PFNGLGETNMINMAXPROC glad_glGetnMinmax;\n#define glGetnMinmax glad_glGetnMinmax\ntypedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC)(void);\nGLAPI PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier;\n#define glTextureBarrier glad_glTextureBarrier\n#endif\n#ifndef GL_VERSION_4_6\n#define GL_VERSION_4_6 1\nGLAPI int GLAD_GL_VERSION_4_6;\ntypedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC)(GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);\nGLAPI PFNGLSPECIALIZESHADERPROC glad_glSpecializeShader;\n#define glSpecializeShader glad_glSpecializeShader\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)(GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\nGLAPI PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount;\n#define glMultiDrawArraysIndirectCount glad_glMultiDrawArraysIndirectCount\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)(GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\nGLAPI PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount;\n#define glMultiDrawElementsIndirectCount glad_glMultiDrawElementsIndirectCount\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC)(GLfloat factor, GLfloat units, GLfloat clamp);\nGLAPI PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp;\n#define glPolygonOffsetClamp glad_glPolygonOffsetClamp\n#endif\n#ifndef GL_ES_VERSION_2_0\n#define GL_ES_VERSION_2_0 1\nGLAPI int GLAD_GL_ES_VERSION_2_0;\n#endif\n#ifndef GL_ES_VERSION_3_0\n#define GL_ES_VERSION_3_0 1\nGLAPI int GLAD_GL_ES_VERSION_3_0;\n#endif\n#ifndef GL_ES_VERSION_3_1\n#define GL_ES_VERSION_3_1 1\nGLAPI int GLAD_GL_ES_VERSION_3_1;\n#endif\n#ifndef GL_ES_VERSION_3_2\n#define GL_ES_VERSION_3_2 1\nGLAPI int GLAD_GL_ES_VERSION_3_2;\ntypedef void (APIENTRYP PFNGLBLENDBARRIERPROC)(void);\nGLAPI PFNGLBLENDBARRIERPROC glad_glBlendBarrier;\n#define glBlendBarrier glad_glBlendBarrier\ntypedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\nGLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;\n#define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox\n#endif\n#define GL_LOWER_LEFT_EXT 0x8CA1\n#define GL_UPPER_LEFT_EXT 0x8CA2\n#define GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E\n#define GL_ZERO_TO_ONE_EXT 0x935F\n#define GL_CLIP_ORIGIN_EXT 0x935C\n#define GL_CLIP_DEPTH_MODE_EXT 0x935D\n#ifndef GL_ARB_clip_control\n#define GL_ARB_clip_control 1\nGLAPI int GLAD_GL_ARB_clip_control;\n#endif\n#ifndef GL_EXT_clip_control\n#define GL_EXT_clip_control 1\nGLAPI int GLAD_GL_EXT_clip_control;\ntypedef void (APIENTRYP PFNGLCLIPCONTROLEXTPROC)(GLenum origin, GLenum depth);\nGLAPI PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT;\n#define glClipControlEXT glad_glClipControlEXT\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/nvml.h",
    "content": "/*\n * Copyright 1993-2019 NVIDIA Corporation.  All rights reserved.\n *\n * NOTICE TO USER:   \n *\n * This source code is subject to NVIDIA ownership rights under U.S. and \n * international Copyright laws.  Users and possessors of this source code \n * are hereby granted a nonexclusive, royalty-free license to use this code \n * in individual and commercial software.\n *\n * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE \n * CODE FOR ANY PURPOSE.  IT IS PROVIDED \"AS IS\" WITHOUT EXPRESS OR \n * IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH \n * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF \n * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.\n * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, \n * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS \n * OF USE, DATA OR PROFITS,  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE \n * OR OTHER TORTIOUS ACTION,  ARISING OUT OF OR IN CONNECTION WITH THE USE \n * OR PERFORMANCE OF THIS SOURCE CODE.  \n *\n * U.S. Government End Users.   This source code is a \"commercial item\" as \n * that term is defined at  48 C.F.R. 2.101 (OCT 1995), consisting  of \n * \"commercial computer  software\"  and \"commercial computer software \n * documentation\" as such terms are  used in 48 C.F.R. 12.212 (SEPT 1995) \n * and is provided to the U.S. Government only as a commercial end item.  \n * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through \n * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the \n * source code with only those rights set forth herein. \n *\n * Any use of this source code in individual and commercial software must \n * include, in the user documentation and internal comments to the code,\n * the above Disclaimer and U.S. Government End Users Notice.\n */\n\n/* \nNVML API Reference\n\nThe NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and \nmanaging various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building\n3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi\ntool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads.\n\nAPI Documentation\n\nSupported platforms:\n- Windows:     Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit\n- Linux:       32-bit and 64-bit\n- Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5\n\nSupported products:\n- Full Support\n    - All Tesla products, starting with the Fermi architecture\n    - All Quadro products, starting with the Fermi architecture\n    - All GRID products, starting with the Kepler architecture\n    - Selected GeForce Titan products\n- Limited Support\n    - All Geforce products, starting with the Fermi architecture\n\nThe NVML library can be found at \\%ProgramW6432\\%\\\\\"NVIDIA Corporation\"\\\\NVSMI\\\\ on Windows. It is\nnot be added to the system path by default. To dynamically link to NVML, add this path to the PATH \nenvironmental variable. To dynamically load NVML, call LoadLibrary with this path.\n\nOn Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit\nand 64 bit NVML libraries will be installed.\n\nOnline documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html\n*/\n\n#ifndef __nvml_nvml_h__\n#define __nvml_nvml_h__\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n * On Windows, set up methods for DLL export\n * define NVML_STATIC_IMPORT when using nvml_loader library\n */\n#if defined _WINDOWS\n    #if !defined NVML_STATIC_IMPORT\n        #if defined NVML_LIB_EXPORT\n            #define DECLDIR __declspec(dllexport)\n        #else\n            #define DECLDIR __declspec(dllimport)\n        #endif\n    #else\n        #define DECLDIR\n    #endif\n#else\n    #define DECLDIR\n#endif\n\n/**\n * NVML API versioning support\n */\n#define NVML_API_VERSION            10\n#define NVML_API_VERSION_STR        \"10\"\n#define nvmlInit                    nvmlInit_v2\n#define nvmlDeviceGetPciInfo        nvmlDeviceGetPciInfo_v3\n#define nvmlDeviceGetCount          nvmlDeviceGetCount_v2\n#define nvmlDeviceGetHandleByIndex  nvmlDeviceGetHandleByIndex_v2\n#define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2\n#define nvmlDeviceGetNvLinkRemotePciInfo nvmlDeviceGetNvLinkRemotePciInfo_v2\n#define nvmlDeviceRemoveGpu         nvmlDeviceRemoveGpu_v2\n#define nvmlDeviceGetGridLicensableFeatures nvmlDeviceGetGridLicensableFeatures_v3\n\n/***************************************************************************************************/\n/** @defgroup nvmlDeviceStructs Device Structs\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Special constant that some fields take when they are not available.\n * Used when only part of the struct is not available.\n *\n * Each structure explicitly states when to check for this value.\n */\n#define NVML_VALUE_NOT_AVAILABLE (-1)\n\ntypedef struct nvmlDevice_st* nvmlDevice_t;\n\n/**\n * Buffer size guaranteed to be large enough for pci bus id\n */\n#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE      32\n\n/**\n * Buffer size guaranteed to be large enough for pci bus id for ::busIdLegacy\n */\n#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE   16\n\n/**\n * PCI information about a GPU device.\n */\ntypedef struct nvmlPciInfo_st\n{\n    char busIdLegacy[NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE]; //!< The legacy tuple domain:bus:device.function PCI identifier (&amp; NULL terminator)\n    unsigned int domain;             //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff\n    unsigned int bus;                //!< The bus on which the device resides, 0 to 0xff\n    unsigned int device;             //!< The device's id on the bus, 0 to 31\n    unsigned int pciDeviceId;        //!< The combined 16-bit device id and 16-bit vendor id\n\n    // Added in NVML 2.285 API\n    unsigned int pciSubSystemId;     //!< The 32-bit Sub System Device ID\n\n    char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (&amp; NULL terminator)\n} nvmlPciInfo_t;\n\n/**\n * PCI format string for ::busIdLegacy\n */\n#define NVML_DEVICE_PCI_BUS_ID_LEGACY_FMT           \"%04X:%02X:%02X.0\"\n\n/**\n * PCI format string for ::busId\n */\n#define NVML_DEVICE_PCI_BUS_ID_FMT                  \"%08X:%02X:%02X.0\"\n\n/**\n * Utility macro for filling the pci bus id format from a nvmlPciInfo_t\n */\n#define NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(pciInfo)    (pciInfo)->domain, \\\n                                                    (pciInfo)->bus,    \\\n                                                    (pciInfo)->device\n\n/**\n * Detailed ECC error counts for a device.\n *\n * @deprecated  Different GPU families can have different memory error counters\n *              See \\ref nvmlDeviceGetMemoryErrorCounter\n */\ntypedef struct nvmlEccErrorCounts_st \n{\n    unsigned long long l1Cache;      //!< L1 cache errors\n    unsigned long long l2Cache;      //!< L2 cache errors\n    unsigned long long deviceMemory; //!< Device memory errors\n    unsigned long long registerFile; //!< Register file errors\n} nvmlEccErrorCounts_t;\n\n/** \n * Utilization information for a device.\n * Each sample period may be between 1 second and 1/6 second, depending on the product being queried.\n */\ntypedef struct nvmlUtilization_st \n{\n    unsigned int gpu;                //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU\n    unsigned int memory;             //!< Percent of time over the past sample period during which global (device) memory was being read or written\n} nvmlUtilization_t;\n\n/** \n * Memory allocation information for a device.\n */\ntypedef struct nvmlMemory_st \n{\n    unsigned long long total;        //!< Total installed FB memory (in bytes)\n    unsigned long long free;         //!< Unallocated FB memory (in bytes)\n    unsigned long long used;         //!< Allocated FB memory (in bytes). Note that the driver/GPU always sets aside a small amount of memory for bookkeeping\n} nvmlMemory_t;\n\n/**\n * BAR1 Memory allocation Information for a device\n */\ntypedef struct nvmlBAR1Memory_st\n{\n    unsigned long long bar1Total;    //!< Total BAR1 Memory (in bytes)\n    unsigned long long bar1Free;     //!< Unallocated BAR1 Memory (in bytes)\n    unsigned long long bar1Used;     //!< Allocated Used Memory (in bytes)\n}nvmlBAR1Memory_t;\n\n/**\n * Information about running compute processes on the GPU\n */\ntypedef struct nvmlProcessInfo_st\n{\n    unsigned int pid;                 //!< Process ID\n    unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes.\n                                      //! Under WDDM, \\ref NVML_VALUE_NOT_AVAILABLE is always reported\n                                      //! because Windows KMD manages all the memory and not the NVIDIA driver\n} nvmlProcessInfo_t;\n\n/**\n * Enum to represent type of bridge chip\n */\ntypedef enum nvmlBridgeChipType_enum\n{\n    NVML_BRIDGE_CHIP_PLX = 0,\n    NVML_BRIDGE_CHIP_BRO4 = 1           \n}nvmlBridgeChipType_t;\n\n/**\n * Maximum number of NvLink links supported \n */\n#define NVML_NVLINK_MAX_LINKS 6\n\n/**\n * Enum to represent the NvLink utilization counter packet units\n */\ntypedef enum nvmlNvLinkUtilizationCountUnits_enum\n{\n    NVML_NVLINK_COUNTER_UNIT_CYCLES =  0,     // count by cycles\n    NVML_NVLINK_COUNTER_UNIT_PACKETS = 1,     // count by packets\n    NVML_NVLINK_COUNTER_UNIT_BYTES   = 2,     // count by bytes\n    NVML_NVLINK_COUNTER_UNIT_RESERVED = 3,    // count reserved for internal use\n    // this must be last\n    NVML_NVLINK_COUNTER_UNIT_COUNT\n} nvmlNvLinkUtilizationCountUnits_t;\n\n/**\n * Enum to represent the NvLink utilization counter packet types to count\n *  ** this is ONLY applicable with the units as packets or bytes\n *  ** as specified in \\a nvmlNvLinkUtilizationCountUnits_t\n *  ** all packet filter descriptions are target GPU centric\n *  ** these can be \"OR'd\" together \n */\ntypedef enum nvmlNvLinkUtilizationCountPktTypes_enum\n{\n    NVML_NVLINK_COUNTER_PKTFILTER_NOP        = 0x1,     // no operation packets\n    NVML_NVLINK_COUNTER_PKTFILTER_READ       = 0x2,     // read packets\n    NVML_NVLINK_COUNTER_PKTFILTER_WRITE      = 0x4,     // write packets\n    NVML_NVLINK_COUNTER_PKTFILTER_RATOM      = 0x8,     // reduction atomic requests\n    NVML_NVLINK_COUNTER_PKTFILTER_NRATOM     = 0x10,    // non-reduction atomic requests\n    NVML_NVLINK_COUNTER_PKTFILTER_FLUSH      = 0x20,    // flush requests\n    NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA   = 0x40,    // responses with data\n    NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80,    // responses without data\n    NVML_NVLINK_COUNTER_PKTFILTER_ALL        = 0xFF     // all packets\n} nvmlNvLinkUtilizationCountPktTypes_t;\n\n/** \n * Struct to define the NVLINK counter controls\n */\ntypedef struct nvmlNvLinkUtilizationControl_st\n{\n    nvmlNvLinkUtilizationCountUnits_t units;\n    nvmlNvLinkUtilizationCountPktTypes_t pktfilter;\n} nvmlNvLinkUtilizationControl_t;\n\n/**\n * Enum to represent NvLink queryable capabilities\n */\ntypedef enum nvmlNvLinkCapability_enum\n{\n    NVML_NVLINK_CAP_P2P_SUPPORTED = 0,     // P2P over NVLink is supported\n    NVML_NVLINK_CAP_SYSMEM_ACCESS = 1,     // Access to system memory is supported\n    NVML_NVLINK_CAP_P2P_ATOMICS   = 2,     // P2P atomics are supported\n    NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3,     // System memory atomics are supported\n    NVML_NVLINK_CAP_SLI_BRIDGE    = 4,     // SLI is supported over this link\n    NVML_NVLINK_CAP_VALID         = 5,     // Link is supported on this device\n    // should be last\n    NVML_NVLINK_CAP_COUNT\n} nvmlNvLinkCapability_t;\n\n/**\n * Enum to represent NvLink queryable error counters\n */\ntypedef enum nvmlNvLinkErrorCounter_enum\n{\n    NVML_NVLINK_ERROR_DL_REPLAY   = 0,     // Data link transmit replay error counter\n    NVML_NVLINK_ERROR_DL_RECOVERY = 1,     // Data link transmit recovery error counter\n    NVML_NVLINK_ERROR_DL_CRC_FLIT = 2,     // Data link receive flow control digit CRC error counter\n    NVML_NVLINK_ERROR_DL_CRC_DATA = 3,     // Data link receive data CRC error counter\n\n    // this must be last\n    NVML_NVLINK_ERROR_COUNT\n} nvmlNvLinkErrorCounter_t;\n\n/**\n * Represents level relationships within a system between two GPUs\n * The enums are spaced to allow for future relationships\n */\ntypedef enum nvmlGpuLevel_enum\n{\n    NVML_TOPOLOGY_INTERNAL           = 0, // e.g. Tesla K80\n    NVML_TOPOLOGY_SINGLE             = 10, // all devices that only need traverse a single PCIe switch\n    NVML_TOPOLOGY_MULTIPLE           = 20, // all devices that need not traverse a host bridge\n    NVML_TOPOLOGY_HOSTBRIDGE         = 30, // all devices that are connected to the same host bridge\n    NVML_TOPOLOGY_NODE               = 40, // all devices that are connected to the same NUMA node but possibly multiple host bridges\n    NVML_TOPOLOGY_SYSTEM             = 50, // all devices in the system\n\n    // there is purposefully no COUNT here because of the need for spacing above\n} nvmlGpuTopologyLevel_t;\n\n/* Compatibility for CPU->NODE renaming */\n#define NVML_TOPOLOGY_CPU NVML_TOPOLOGY_NODE\n\n/* P2P Capability Index Status*/\ntypedef enum nvmlGpuP2PStatus_enum\n{\n    NVML_P2P_STATUS_OK     = 0,\n    NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED,\n    NVML_P2P_STATUS_GPU_NOT_SUPPORTED,\n    NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED,\n    NVML_P2P_STATUS_DISABLED_BY_REGKEY,\n    NVML_P2P_STATUS_NOT_SUPPORTED,\n    NVML_P2P_STATUS_UNKNOWN\n\n} nvmlGpuP2PStatus_t;\n\n/* P2P Capability Index*/\ntypedef enum nvmlGpuP2PCapsIndex_enum\n{\n    NVML_P2P_CAPS_INDEX_READ = 0,\n    NVML_P2P_CAPS_INDEX_WRITE,\n    NVML_P2P_CAPS_INDEX_NVLINK,\n    NVML_P2P_CAPS_INDEX_ATOMICS,\n    NVML_P2P_CAPS_INDEX_PROP,\n    NVML_P2P_CAPS_INDEX_UNKNOWN\n}nvmlGpuP2PCapsIndex_t;\n\n/**\n * Maximum limit on Physical Bridges per Board\n */\n#define NVML_MAX_PHYSICAL_BRIDGE                         (128)\n\n/**\n * Information about the Bridge Chip Firmware\n */\ntypedef struct nvmlBridgeChipInfo_st\n{\n    nvmlBridgeChipType_t type;                  //!< Type of Bridge Chip \n    unsigned int fwVersion;                     //!< Firmware Version. 0=Version is unavailable\n}nvmlBridgeChipInfo_t;\n\n/**\n * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate \n * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth.\n */\ntypedef struct nvmlBridgeChipHierarchy_st\n{\n    unsigned char  bridgeCount;                 //!< Number of Bridge Chips on the Board\n    nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board\n}nvmlBridgeChipHierarchy_t;\n\n/**\n *  Represents Type of Sampling Event\n */\ntypedef enum nvmlSamplingType_enum\n{\n    NVML_TOTAL_POWER_SAMPLES        = 0, //!< To represent total power drawn by GPU\n    NVML_GPU_UTILIZATION_SAMPLES    = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU\n    NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written\n    NVML_ENC_UTILIZATION_SAMPLES    = 3, //!< To represent percent of time during which NVENC remains busy\n    NVML_DEC_UTILIZATION_SAMPLES    = 4, //!< To represent percent of time during which NVDEC remains busy            \n    NVML_PROCESSOR_CLK_SAMPLES      = 5, //!< To represent processor clock samples\n    NVML_MEMORY_CLK_SAMPLES         = 6, //!< To represent memory clock samples\n            \n    // Keep this last\n    NVML_SAMPLINGTYPE_COUNT               \n}nvmlSamplingType_t;\n\n/**\n * Represents the queryable PCIe utilization counters\n */\ntypedef enum nvmlPcieUtilCounter_enum\n{\n    NVML_PCIE_UTIL_TX_BYTES             = 0, // 1KB granularity\n    NVML_PCIE_UTIL_RX_BYTES             = 1, // 1KB granularity\n    \n    // Keep this last\n    NVML_PCIE_UTIL_COUNT\n} nvmlPcieUtilCounter_t;\n\n/**\n * Represents the type for sample value returned\n */\ntypedef enum nvmlValueType_enum \n{\n    NVML_VALUE_TYPE_DOUBLE = 0,\n    NVML_VALUE_TYPE_UNSIGNED_INT = 1,\n    NVML_VALUE_TYPE_UNSIGNED_LONG = 2,\n    NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3,\n    NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4,\n\n    // Keep this last\n    NVML_VALUE_TYPE_COUNT\n}nvmlValueType_t;\n\n\n/**\n * Union to represent different types of Value\n */\ntypedef union nvmlValue_st\n{\n    double dVal;                    //!< If the value is double\n    unsigned int uiVal;             //!< If the value is unsigned int\n    unsigned long ulVal;            //!< If the value is unsigned long\n    unsigned long long ullVal;      //!< If the value is unsigned long long\n    signed long long sllVal;        //!< If the value is signed long long\n}nvmlValue_t;\n\n/**\n * Information for Sample\n */\ntypedef struct nvmlSample_st \n{\n    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds\n    nvmlValue_t sampleValue;        //!< Sample Value\n}nvmlSample_t;\n\n/**\n * Represents type of perf policy for which violation times can be queried \n */\ntypedef enum nvmlPerfPolicyType_enum\n{\n    NVML_PERF_POLICY_POWER = 0,              //!< How long did power violations cause the GPU to be below application clocks\n    NVML_PERF_POLICY_THERMAL = 1,            //!< How long did thermal violations cause the GPU to be below application clocks\n    NVML_PERF_POLICY_SYNC_BOOST = 2,         //!< How long did sync boost cause the GPU to be below application clocks\n    NVML_PERF_POLICY_BOARD_LIMIT = 3,        //!< How long did the board limit cause the GPU to be below application clocks\n    NVML_PERF_POLICY_LOW_UTILIZATION = 4,    //!< How long did low utilization cause the GPU to be below application clocks\n    NVML_PERF_POLICY_RELIABILITY = 5,        //!< How long did the board reliability limit cause the GPU to be below application clocks\n\n    NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10,  //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above)\n    NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks\n\n    // Keep this last\n    NVML_PERF_POLICY_COUNT\n}nvmlPerfPolicyType_t;\n\n/**\n * Struct to hold perf policy violation status data\n */\ntypedef struct nvmlViolationTime_st\n{\n    unsigned long long referenceTime;  //!< referenceTime represents CPU timestamp in microseconds\n    unsigned long long violationTime;  //!< violationTime in Nanoseconds\n}nvmlViolationTime_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlDeviceEnumvs Device Enums\n *  @{\n */\n/***************************************************************************************************/\n\n/** \n * Generic enable/disable enum. \n */\ntypedef enum nvmlEnableState_enum \n{\n    NVML_FEATURE_DISABLED    = 0,     //!< Feature disabled \n    NVML_FEATURE_ENABLED     = 1      //!< Feature enabled\n} nvmlEnableState_t;\n\n//! Generic flag used to specify the default behavior of some functions. See description of particular functions for details.\n#define nvmlFlagDefault     0x00      \n//! Generic flag used to force some behavior. See description of particular functions for details.\n#define nvmlFlagForce       0x01      \n\n/**\n *  * The Brand of the GPU\n *   */\ntypedef enum nvmlBrandType_enum\n{\n    NVML_BRAND_UNKNOWN = 0, \n    NVML_BRAND_QUADRO  = 1,\n    NVML_BRAND_TESLA   = 2,\n    NVML_BRAND_NVS     = 3,\n    NVML_BRAND_GRID    = 4,\n    NVML_BRAND_GEFORCE = 5,\n    NVML_BRAND_TITAN   = 6,\n\n    // Keep this last\n    NVML_BRAND_COUNT\n} nvmlBrandType_t;\n\n/**\n * Temperature thresholds.\n */\ntypedef enum nvmlTemperatureThresholds_enum\n{\n    NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0,    // Temperature at which the GPU will shut down\n                                                // for HW protection\n    NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1,    // Temperature at which the GPU will begin HW slowdown\n    NVML_TEMPERATURE_THRESHOLD_MEM_MAX  = 2,    // Memory Temperature at which the GPU will begin SW slowdown\n    NVML_TEMPERATURE_THRESHOLD_GPU_MAX  = 3,    // GPU Temperature at which the GPU can be throttled below base clock\n    // Keep this last\n    NVML_TEMPERATURE_THRESHOLD_COUNT\n} nvmlTemperatureThresholds_t;\n\n/** \n * Temperature sensors. \n */\ntypedef enum nvmlTemperatureSensors_enum \n{\n    NVML_TEMPERATURE_GPU      = 0,    //!< Temperature sensor for the GPU die\n    \n    // Keep this last\n    NVML_TEMPERATURE_COUNT\n} nvmlTemperatureSensors_t;\n\n/** \n * Compute mode. \n *\n * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0.\n * Earlier CUDA versions supported a single exclusive mode, \n * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond.\n */\ntypedef enum nvmlComputeMode_enum \n{\n    NVML_COMPUTEMODE_DEFAULT           = 0,  //!< Default compute mode -- multiple contexts per device\n    NVML_COMPUTEMODE_EXCLUSIVE_THREAD  = 1,  //!< Support Removed\n    NVML_COMPUTEMODE_PROHIBITED        = 2,  //!< Compute-prohibited mode -- no contexts per device\n    NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3,  //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time\n    \n    // Keep this last\n    NVML_COMPUTEMODE_COUNT\n} nvmlComputeMode_t;\n\n/** \n * ECC bit types.\n *\n * @deprecated See \\ref nvmlMemoryErrorType_t for a more flexible type\n */\n#define nvmlEccBitType_t nvmlMemoryErrorType_t\n\n/**\n * Single bit ECC errors\n *\n * @deprecated Mapped to \\ref NVML_MEMORY_ERROR_TYPE_CORRECTED\n */\n#define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED\n\n/**\n * Double bit ECC errors\n *\n * @deprecated Mapped to \\ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED\n */\n#define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED\n\n/**\n * Memory error types\n */\ntypedef enum nvmlMemoryErrorType_enum\n{\n    /**\n     * A memory error that was corrected\n     * \n     * For ECC errors, these are single bit errors\n     * For Texture memory, these are errors fixed by resend\n     */\n    NVML_MEMORY_ERROR_TYPE_CORRECTED = 0,\n    /**\n     * A memory error that was not corrected\n     * \n     * For ECC errors, these are double bit errors\n     * For Texture memory, these are errors where the resend fails\n     */\n    NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1,\n    \n    \n    // Keep this last\n    NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types\n\n} nvmlMemoryErrorType_t;\n\n/** \n * ECC counter types. \n *\n * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent.\n *       On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver \n *       client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app\n *       is run.\n */\ntypedef enum nvmlEccCounterType_enum \n{\n    NVML_VOLATILE_ECC      = 0,      //!< Volatile counts are reset each time the driver loads.\n    NVML_AGGREGATE_ECC     = 1,      //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device)\n    \n    // Keep this last\n    NVML_ECC_COUNTER_TYPE_COUNT      //!< Count of memory counter types\n} nvmlEccCounterType_t;\n\n/** \n * Clock types. \n * \n * All speeds are in Mhz.\n */\ntypedef enum nvmlClockType_enum \n{\n    NVML_CLOCK_GRAPHICS  = 0,        //!< Graphics clock domain\n    NVML_CLOCK_SM        = 1,        //!< SM clock domain\n    NVML_CLOCK_MEM       = 2,        //!< Memory clock domain\n    NVML_CLOCK_VIDEO     = 3,        //!< Video encoder/decoder clock domain\n    \n    // Keep this last\n    NVML_CLOCK_COUNT //!< Count of clock types\n} nvmlClockType_t;\n\n/**\n * Clock Ids.  These are used in combination with nvmlClockType_t\n * to specify a single clock value.\n */\ntypedef enum nvmlClockId_enum\n{\n    NVML_CLOCK_ID_CURRENT            = 0,   //!< Current actual clock value\n    NVML_CLOCK_ID_APP_CLOCK_TARGET   = 1,   //!< Target application clock\n    NVML_CLOCK_ID_APP_CLOCK_DEFAULT  = 2,   //!< Default application clock target\n    NVML_CLOCK_ID_CUSTOMER_BOOST_MAX = 3,   //!< OEM-defined maximum clock rate\n\n    //Keep this last\n    NVML_CLOCK_ID_COUNT //!< Count of Clock Ids.\n} nvmlClockId_t;\n\n/** \n * Driver models. \n *\n * Windows only.\n */\ntypedef enum nvmlDriverModel_enum \n{\n    NVML_DRIVER_WDDM      = 0,       //!< WDDM driver model -- GPU treated as a display device\n    NVML_DRIVER_WDM       = 1        //!< WDM (TCC) model (recommended) -- GPU treated as a generic device\n} nvmlDriverModel_t;\n\n/**\n * Allowed PStates.\n */\ntypedef enum nvmlPStates_enum \n{\n    NVML_PSTATE_0               = 0,       //!< Performance state 0 -- Maximum Performance\n    NVML_PSTATE_1               = 1,       //!< Performance state 1 \n    NVML_PSTATE_2               = 2,       //!< Performance state 2\n    NVML_PSTATE_3               = 3,       //!< Performance state 3\n    NVML_PSTATE_4               = 4,       //!< Performance state 4\n    NVML_PSTATE_5               = 5,       //!< Performance state 5\n    NVML_PSTATE_6               = 6,       //!< Performance state 6\n    NVML_PSTATE_7               = 7,       //!< Performance state 7\n    NVML_PSTATE_8               = 8,       //!< Performance state 8\n    NVML_PSTATE_9               = 9,       //!< Performance state 9\n    NVML_PSTATE_10              = 10,      //!< Performance state 10\n    NVML_PSTATE_11              = 11,      //!< Performance state 11\n    NVML_PSTATE_12              = 12,      //!< Performance state 12\n    NVML_PSTATE_13              = 13,      //!< Performance state 13\n    NVML_PSTATE_14              = 14,      //!< Performance state 14\n    NVML_PSTATE_15              = 15,      //!< Performance state 15 -- Minimum Performance \n    NVML_PSTATE_UNKNOWN         = 32       //!< Unknown performance state\n} nvmlPstates_t;\n\n/**\n * GPU Operation Mode\n *\n * GOM allows to reduce power usage and optimize GPU throughput by disabling GPU features.\n *\n * Each GOM is designed to meet specific user needs.\n */\ntypedef enum nvmlGom_enum\n{\n    NVML_GOM_ALL_ON                    = 0, //!< Everything is enabled and running at full speed\n\n    NVML_GOM_COMPUTE                   = 1, //!< Designed for running only compute tasks. Graphics operations\n                                            //!< are not allowed\n\n    NVML_GOM_LOW_DP                    = 2  //!< Designed for running graphics applications that don't require\n                                            //!< high bandwidth double precision\n} nvmlGpuOperationMode_t;\n\n/** \n * Available infoROM objects.\n */\ntypedef enum nvmlInforomObject_enum \n{\n    NVML_INFOROM_OEM            = 0,       //!< An object defined by OEM\n    NVML_INFOROM_ECC            = 1,       //!< The ECC object determining the level of ECC support\n    NVML_INFOROM_POWER          = 2,       //!< The power management object\n\n    // Keep this last\n    NVML_INFOROM_COUNT                     //!< This counts the number of infoROM objects the driver knows about\n} nvmlInforomObject_t;\n\n/** \n * Return values for NVML API calls. \n */\ntypedef enum nvmlReturn_enum \n{\n    // cppcheck-suppress *\n    NVML_SUCCESS = 0,                   //!< The operation was successful\n    NVML_ERROR_UNINITIALIZED = 1,       //!< NVML was not first initialized with nvmlInit()\n    NVML_ERROR_INVALID_ARGUMENT = 2,    //!< A supplied argument is invalid\n    NVML_ERROR_NOT_SUPPORTED = 3,       //!< The requested operation is not available on target device\n    NVML_ERROR_NO_PERMISSION = 4,       //!< The current user does not have permission for operation\n    NVML_ERROR_ALREADY_INITIALIZED = 5, //!< Deprecated: Multiple initializations are now allowed through ref counting\n    NVML_ERROR_NOT_FOUND = 6,           //!< A query to find an object was unsuccessful\n    NVML_ERROR_INSUFFICIENT_SIZE = 7,   //!< An input argument is not large enough\n    NVML_ERROR_INSUFFICIENT_POWER = 8,  //!< A device's external power cables are not properly attached\n    NVML_ERROR_DRIVER_NOT_LOADED = 9,   //!< NVIDIA driver is not loaded\n    NVML_ERROR_TIMEOUT = 10,            //!< User provided timeout passed\n    NVML_ERROR_IRQ_ISSUE = 11,          //!< NVIDIA Kernel detected an interrupt issue with a GPU\n    NVML_ERROR_LIBRARY_NOT_FOUND = 12,  //!< NVML Shared Library couldn't be found or loaded\n    NVML_ERROR_FUNCTION_NOT_FOUND = 13, //!< Local version of NVML doesn't implement this function\n    NVML_ERROR_CORRUPTED_INFOROM = 14,  //!< infoROM is corrupted\n    NVML_ERROR_GPU_IS_LOST = 15,        //!< The GPU has fallen off the bus or has otherwise become inaccessible\n    NVML_ERROR_RESET_REQUIRED = 16,     //!< The GPU requires a reset before it can be used again\n    NVML_ERROR_OPERATING_SYSTEM = 17,   //!< The GPU control device has been blocked by the operating system/cgroups\n    NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18,   //!< RM detects a driver/library version mismatch\n    NVML_ERROR_IN_USE = 19,             //!< An operation cannot be performed because the GPU is currently in use\n    NVML_ERROR_MEMORY = 20,             //!< Insufficient memory\n    NVML_ERROR_NO_DATA = 21,            //!<No data\n    NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22,    //!< The requested vgpu operation is not available on target device, becasue ECC is enabled\n    NVML_ERROR_UNKNOWN = 999            //!< An internal driver error occurred\n} nvmlReturn_t;\n\n/**\n * See \\ref nvmlDeviceGetMemoryErrorCounter\n */\ntypedef enum nvmlMemoryLocation_enum\n{\n    NVML_MEMORY_LOCATION_L1_CACHE        = 0,    //!< GPU L1 Cache\n    NVML_MEMORY_LOCATION_L2_CACHE        = 1,    //!< GPU L2 Cache\n    NVML_MEMORY_LOCATION_DRAM            = 2,    //!< Turing+ DRAM\n    NVML_MEMORY_LOCATION_DEVICE_MEMORY   = 2,    //!< GPU Device Memory\n    NVML_MEMORY_LOCATION_REGISTER_FILE   = 3,    //!< GPU Register File\n    NVML_MEMORY_LOCATION_TEXTURE_MEMORY  = 4,    //!< GPU Texture Memory\n    NVML_MEMORY_LOCATION_TEXTURE_SHM     = 5,    //!< Shared memory\n    NVML_MEMORY_LOCATION_CBU             = 6,    //!< CBU\n    NVML_MEMORY_LOCATION_SRAM            = 7,    //!< Turing+ SRAM\n    // Keep this last\n    NVML_MEMORY_LOCATION_COUNT              //!< This counts the number of memory locations the driver knows about\n} nvmlMemoryLocation_t;\n\n/**\n * Causes for page retirement\n */\ntypedef enum nvmlPageRetirementCause_enum\n{\n    NVML_PAGE_RETIREMENT_CAUSE_MULTIPLE_SINGLE_BIT_ECC_ERRORS = 0, //!< Page was retired due to multiple single bit ECC error\n    NVML_PAGE_RETIREMENT_CAUSE_DOUBLE_BIT_ECC_ERROR = 1,           //!< Page was retired due to double bit ECC error\n\n    // Keep this last\n    NVML_PAGE_RETIREMENT_CAUSE_COUNT\n} nvmlPageRetirementCause_t;\n\n/**\n * API types that allow changes to default permission restrictions\n */\ntypedef enum nvmlRestrictedAPI_enum\n{\n    NVML_RESTRICTED_API_SET_APPLICATION_CLOCKS = 0,   //!< APIs that change application clocks, see nvmlDeviceSetApplicationsClocks \n                                                      //!< and see nvmlDeviceResetApplicationsClocks\n    NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS = 1,  //!< APIs that enable/disable Auto Boosted clocks\n                                                      //!< see nvmlDeviceSetAutoBoostedClocksEnabled\n    // Keep this last\n    NVML_RESTRICTED_API_COUNT\n} nvmlRestrictedAPI_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @addtogroup gridVirtual\n *  @{\n */\n/***************************************************************************************************/\n/** @defgroup nvmlGridEnums GRID Virtualization Enums\n *  @{\n */\n/***************************************************************************************************/\n\n/*!\n * GPU virtualization mode types.\n */\ntypedef enum nvmlGpuVirtualizationMode {\n    NVML_GPU_VIRTUALIZATION_MODE_NONE = 0,  //!< Represents Bare Metal GPU\n    NVML_GPU_VIRTUALIZATION_MODE_PASSTHROUGH = 1,  //!< Device is associated with GPU-Passthorugh\n    NVML_GPU_VIRTUALIZATION_MODE_VGPU = 2,  //!< Device is associated with vGPU inside virtual machine.\n    NVML_GPU_VIRTUALIZATION_MODE_HOST_VGPU = 3,  //!< Device is associated with VGX hypervisor in vGPU mode\n    NVML_GPU_VIRTUALIZATION_MODE_HOST_VSGA = 4,  //!< Device is associated with VGX hypervisor in vSGA mode\n} nvmlGpuVirtualizationMode_t;\n\n/**\n * Host vGPU modes\n */\ntypedef enum nvmlHostVgpuMode_enum\n{\n    NVML_HOST_VGPU_MODE_NON_SRIOV    = 0,     //!< Non SR-IOV mode\n    NVML_HOST_VGPU_MODE_SRIOV        = 1      //!< SR-IOV mode\n} nvmlHostVgpuMode_t;\n\n/*!\n * Types of VM identifiers\n */\ntypedef enum nvmlVgpuVmIdType {\n    NVML_VGPU_VM_ID_DOMAIN_ID = 0, //!< VM ID represents DOMAIN ID\n    NVML_VGPU_VM_ID_UUID = 1,      //!< VM ID represents UUID\n} nvmlVgpuVmIdType_t;\n\n/**\n * vGPU GUEST info state.\n */\ntypedef enum nvmlVgpuGuestInfoState_enum\n{\n    NVML_VGPU_INSTANCE_GUEST_INFO_STATE_UNINITIALIZED = 0,  //!< Guest-dependent fields uninitialized\n    NVML_VGPU_INSTANCE_GUEST_INFO_STATE_INITIALIZED   = 1,  //!< Guest-dependent fields initialized\n} nvmlVgpuGuestInfoState_t;\n\n/**\n * GRID license feature code\n */\ntypedef enum {\n    NVML_GRID_LICENSE_FEATURE_CODE_VGPU = 1,         //!< Virtual GPU\n    NVML_GRID_LICENSE_FEATURE_CODE_VWORKSTATION = 2  //!< Virtual Workstation\n} nvmlGridLicenseFeatureCode_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlVgpuConstants GRID Virtualization Constants\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlVgpuTypeGetLicense\n */\n#define NVML_GRID_LICENSE_BUFFER_SIZE       128\n\n#define NVML_VGPU_NAME_BUFFER_SIZE          64\n\n#define NVML_GRID_LICENSE_FEATURE_MAX_COUNT 3\n\n/*!\n * Macros for vGPU instance's virtualization capabilities bitfield.\n */\n#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION         0:0\n#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_NO      0x0\n#define NVML_VGPU_VIRTUALIZATION_CAP_MIGRATION_YES     0x1\n\n/*!\n * Macros for pGPU's virtualization capabilities bitfield.\n */\n#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION         0:0\n#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_NO      0x0\n#define NVML_VGPU_PGPU_VIRTUALIZATION_CAP_MIGRATION_YES     0x1\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlVgpuStructs GRID Virtualization Structs\n *  @{\n */\n/***************************************************************************************************/\n\ntypedef unsigned int nvmlVgpuTypeId_t;\n\ntypedef unsigned int nvmlVgpuInstance_t;\n\n/**\n * Structure to store Utilization Value and vgpuInstance\n */\ntypedef struct nvmlVgpuInstanceUtilizationSample_st\n{\n    nvmlVgpuInstance_t vgpuInstance;    //!< vGPU Instance\n    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds\n    nvmlValue_t smUtil;                 //!< SM (3D/Compute) Util Value\n    nvmlValue_t memUtil;                //!< Frame Buffer Memory Util Value\n    nvmlValue_t encUtil;                //!< Encoder Util Value\n    nvmlValue_t decUtil;                //!< Decoder Util Value\n} nvmlVgpuInstanceUtilizationSample_t;\n\n/**\n * Structure to store Utilization Value, vgpuInstance and subprocess information\n */\ntypedef struct nvmlVgpuProcessUtilizationSample_st\n{\n    nvmlVgpuInstance_t vgpuInstance;                //!< vGPU Instance\n    unsigned int pid;                               //!< PID of process running within the vGPU VM\n    char processName[NVML_VGPU_NAME_BUFFER_SIZE];   //!< Name of process running within the vGPU VM\n    unsigned long long timeStamp;                   //!< CPU Timestamp in microseconds\n    unsigned int smUtil;                            //!< SM (3D/Compute) Util Value\n    unsigned int memUtil;                           //!< Frame Buffer Memory Util Value\n    unsigned int encUtil;                           //!< Encoder Util Value\n    unsigned int decUtil;                           //!< Decoder Util Value\n} nvmlVgpuProcessUtilizationSample_t;\n\n/**\n * Structure to store utilization value and process Id\n */\ntypedef struct nvmlProcessUtilizationSample_st\n{\n    unsigned int pid;                   //!< PID of process\n    unsigned long long timeStamp;       //!< CPU Timestamp in microseconds\n    unsigned int smUtil;                //!< SM (3D/Compute) Util Value\n    unsigned int memUtil;               //!< Frame Buffer Memory Util Value\n    unsigned int encUtil;               //!< Encoder Util Value\n    unsigned int decUtil;               //!< Decoder Util Value\n} nvmlProcessUtilizationSample_t;\n\n/**\n * Structure containing GRID licensable feature information\n */\ntypedef struct nvmlGridLicensableFeature_st\n{\n    nvmlGridLicenseFeatureCode_t    featureCode;                                 //!< Licensed feature code\n    unsigned int                    featureState;                                //!< Non-zero if feature is currently licensed, otherwise zero\n    char                            licenseInfo[NVML_GRID_LICENSE_BUFFER_SIZE];\n    char                            productName[NVML_GRID_LICENSE_BUFFER_SIZE];\n    unsigned int                    featureEnabled;                              //!< Non-zero if feature is enabled, otherwise zero\n} nvmlGridLicensableFeature_t;\n\n/**\n * Structure to store GRID licensable features\n */\ntypedef struct nvmlGridLicensableFeatures_st\n{\n    int                         isGridLicenseSupported;                                       //!< Non-zero if GRID Software Licensing is supported on the system, otherwise zero\n    unsigned int                licensableFeaturesCount;                                      //!< Entries returned in \\a gridLicensableFeatures array\n    nvmlGridLicensableFeature_t gridLicensableFeatures[NVML_GRID_LICENSE_FEATURE_MAX_COUNT];  //!< Array of GRID licensable features.\n} nvmlGridLicensableFeatures_t;\n\n/** @} */\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlFieldValueEnums Field Value Enums\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Field Identifiers.\n *\n * All Identifiers pertain to a device. Each ID is only used once and is guaranteed never to change.\n */\n#define NVML_FI_DEV_ECC_CURRENT           1   //!< Current ECC mode. 1=Active. 0=Inactive\n#define NVML_FI_DEV_ECC_PENDING           2   //!< Pending ECC mode. 1=Active. 0=Inactive\n/* ECC Count Totals */\n#define NVML_FI_DEV_ECC_SBE_VOL_TOTAL     3   //!< Total single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_TOTAL     4   //!< Total double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_TOTAL     5   //!< Total single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_TOTAL     6   //!< Total double bit aggregate (persistent) ECC errors\n/* Individual ECC locations */\n#define NVML_FI_DEV_ECC_SBE_VOL_L1        7   //!< L1 cache single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_L1        8   //!< L1 cache double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_VOL_L2        9   //!< L2 cache single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_L2        10  //!< L2 cache double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_VOL_DEV       11  //!< Device memory single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_DEV       12  //!< Device memory double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_VOL_REG       13  //!< Register file single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_REG       14  //!< Register file double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_VOL_TEX       15  //!< Texture memory single bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_TEX       16  //!< Texture memory double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_DBE_VOL_CBU       17  //!< CBU double bit volatile ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_L1        18  //!< L1 cache single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_L1        19  //!< L1 cache double bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_L2        20  //!< L2 cache single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_L2        21  //!< L2 cache double bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_DEV       22  //!< Device memory single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_DEV       23  //!< Device memory double bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_REG       24  //!< Register File single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_REG       25  //!< Register File double bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_SBE_AGG_TEX       26  //!< Texture memory single bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_TEX       27  //!< Texture memory double bit aggregate (persistent) ECC errors\n#define NVML_FI_DEV_ECC_DBE_AGG_CBU       28  //!< CBU double bit aggregate ECC errors\n\n/* Page Retirement */\n#define NVML_FI_DEV_RETIRED_SBE           29  //!< Number of retired pages because of single bit errors\n#define NVML_FI_DEV_RETIRED_DBE           30  //!< Number of retired pages because of double bit errors\n#define NVML_FI_DEV_RETIRED_PENDING       31  //!< If any pages are pending retirement. 1=yes. 0=no.\n\n/* NvLink Flit Error Counters */\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L0    32 //!< NVLink flow control CRC  Error Counter for Lane 0\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L1    33 //!< NVLink flow control CRC  Error Counter for Lane 1\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L2    34 //!< NVLink flow control CRC  Error Counter for Lane 2\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L3    35 //!< NVLink flow control CRC  Error Counter for Lane 3\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L4    36 //!< NVLink flow control CRC  Error Counter for Lane 4\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_L5    37 //!< NVLink flow control CRC  Error Counter for Lane 5\n#define NVML_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL 38 //!< NVLink flow control CRC  Error Counter total for all Lanes\n\n/* NvLink CRC Data Error Counters */\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L0    39 //!< NVLink data CRC Error Counter for Lane 0\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L1    40 //!< NVLink data CRC Error Counter for Lane 1\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L2    41 //!< NVLink data CRC Error Counter for Lane 2\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L3    42 //!< NVLink data CRC Error Counter for Lane 3\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L4    43 //!< NVLink data CRC Error Counter for Lane 4\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_L5    44 //!< NVLink data CRC Error Counter for Lane 5\n#define NVML_FI_DEV_NVLINK_CRC_DATA_ERROR_COUNT_TOTAL 45 //!< NvLink data CRC Error Counter total for all Lanes\n\n/* NvLink Replay Error Counters */\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L0      46 //!< NVLink Replay Error Counter for Lane 0\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L1      47 //!< NVLink Replay Error Counter for Lane 1\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L2      48 //!< NVLink Replay Error Counter for Lane 2\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L3      49 //!< NVLink Replay Error Counter for Lane 3\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L4      50 //!< NVLink Replay Error Counter for Lane 4\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_L5      51 //!< NVLink Replay Error Counter for Lane 5\n#define NVML_FI_DEV_NVLINK_REPLAY_ERROR_COUNT_TOTAL   52 //!< NVLink Replay Error Counter total for all Lanes\n\n/* NvLink Recovery Error Counters */\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L0    53 //!< NVLink Recovery Error Counter for Lane 0\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L1    54 //!< NVLink Recovery Error Counter for Lane 1\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L2    55 //!< NVLink Recovery Error Counter for Lane 2\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L3    56 //!< NVLink Recovery Error Counter for Lane 3\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L4    57 //!< NVLink Recovery Error Counter for Lane 4\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_L5    58 //!< NVLink Recovery Error Counter for Lane 5\n#define NVML_FI_DEV_NVLINK_RECOVERY_ERROR_COUNT_TOTAL 59 //!< NVLink Recovery Error Counter total for all Lanes\n\n/* NvLink Bandwidth Counters */\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L0     60 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 0\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L1     61 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 1\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L2     62 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 2\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L3     63 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 3\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L4     64 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 4\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_L5     65 //!< NVLink Bandwidth Counter for Counter Set 0, Lane 5\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C0_TOTAL  66 //!< NVLink Bandwidth Counter Total for Counter Set 0, All Lanes\n\n/* NvLink Bandwidth Counters */\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L0     67 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 0\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L1     68 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 1\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L2     69 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 2\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L3     70 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 3\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L4     71 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 4\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_L5     72 //!< NVLink Bandwidth Counter for Counter Set 1, Lane 5\n#define NVML_FI_DEV_NVLINK_BANDWIDTH_C1_TOTAL  73 //!< NVLink Bandwidth Counter Total for Counter Set 1, All Lanes\n\n/* NVML Perf Policy Counters */\n#define NVML_FI_DEV_PERF_POLICY_POWER              74   //!< Perf Policy Counter for Power Policy\n#define NVML_FI_DEV_PERF_POLICY_THERMAL            75   //!< Perf Policy Counter for Thermal Policy\n#define NVML_FI_DEV_PERF_POLICY_SYNC_BOOST         76   //!< Perf Policy Counter for Sync boost Policy\n#define NVML_FI_DEV_PERF_POLICY_BOARD_LIMIT        77   //!< Perf Policy Counter for Board Limit\n#define NVML_FI_DEV_PERF_POLICY_LOW_UTILIZATION    78   //!< Perf Policy Counter for Low GPU Utilization Policy\n#define NVML_FI_DEV_PERF_POLICY_RELIABILITY        79   //!< Perf Policy Counter for Reliability Policy\n#define NVML_FI_DEV_PERF_POLICY_TOTAL_APP_CLOCKS   80   //!< Perf Policy Counter for Total App Clock Policy\n#define NVML_FI_DEV_PERF_POLICY_TOTAL_BASE_CLOCKS  81   //!< Perf Policy Counter for Total Base Clocks Policy\n\n/* Memory temperatures */\n#define NVML_FI_DEV_MEMORY_TEMP  82 //!< Memory temperature for the device\n\n/* Energy Counter */\n#define NVML_FI_DEV_TOTAL_ENERGY_CONSUMPTION 83 //!< Total energy consumption for the GPU in mJ since the driver was last reloaded\n\n/* NVLink Speed */\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L0     84  //!< NVLink Speed in MBps for Link 0\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L1     85  //!< NVLink Speed in MBps for Link 1\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L2     86  //!< NVLink Speed in MBps for Link 2\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L3     87  //!< NVLink Speed in MBps for Link 3\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L4     88  //!< NVLink Speed in MBps for Link 4\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_L5     89  //!< NVLink Speed in MBps for Link 5\n#define NVML_FI_DEV_NVLINK_SPEED_MBPS_COMMON 90  //!< Common NVLink Speed in MBps for active links\n\n#define NVML_FI_DEV_NVLINK_LINK_COUNT        91  //!< Number of NVLinks present on the device\n\n#define NVML_FI_DEV_RETIRED_PENDING_SBE      92  //!< If any pages are pending retirement due to SBE. 1=yes. 0=no.\n#define NVML_FI_DEV_RETIRED_PENDING_DBE      93  //!< If any pages are pending retirement due to DBE. 1=yes. 0=no.\n\n#define NVML_FI_DEV_PCIE_REPLAY_COUNTER             94  //!< PCIe replay counter\n#define NVML_FI_DEV_PCIE_REPLAY_ROLLOVER_COUNTER    95  //!< PCIe replay rollover counter\n\n#define NVML_FI_MAX 96 //!< One greater than the largest field ID defined above\n\n/**\n * Information for a Field Value Sample\n */\ntypedef struct nvmlFieldValue_st\n{\n    unsigned int fieldId;       //!< ID of the NVML field to retrieve. This must be set before any call that uses this struct. See the constants starting with NVML_FI_ above.\n    unsigned int unused;        //!< Currently unused. This should be initialized to 0 by the caller before any API call\n    long long timestamp;        //!< CPU Timestamp of this value in microseconds since 1970\n    long long latencyUsec;      //!< How long this field value took to update (in usec) within NVML. This may be averaged across several fields that are serviced by the same driver call.\n    nvmlValueType_t valueType;  //!< Type of the value stored in value\n    nvmlReturn_t nvmlReturn;    //!< Return code for retrieving this value. This must be checked before looking at value, as value is undefined if nvmlReturn != NVML_SUCCESS\n    nvmlValue_t value;          //!< Value for this field. This is only valid if nvmlReturn == NVML_SUCCESS\n} nvmlFieldValue_t;\n\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlUnitStructs Unit Structs\n *  @{\n */\n/***************************************************************************************************/\n\ntypedef struct nvmlUnit_st* nvmlUnit_t;\n\n/** \n * Description of HWBC entry \n */\ntypedef struct nvmlHwbcEntry_st \n{\n    unsigned int hwbcId;\n    char firmwareVersion[32];\n} nvmlHwbcEntry_t;\n\n/** \n * Fan state enum. \n */\ntypedef enum nvmlFanState_enum \n{\n    NVML_FAN_NORMAL       = 0,     //!< Fan is working properly\n    NVML_FAN_FAILED       = 1      //!< Fan has failed\n} nvmlFanState_t;\n\n/** \n * Led color enum. \n */\ntypedef enum nvmlLedColor_enum \n{\n    NVML_LED_COLOR_GREEN       = 0,     //!< GREEN, indicates good health\n    NVML_LED_COLOR_AMBER       = 1      //!< AMBER, indicates problem\n} nvmlLedColor_t;\n\n\n/** \n * LED states for an S-class unit.\n */\ntypedef struct nvmlLedState_st \n{\n    char cause[256];               //!< If amber, a text description of the cause\n    nvmlLedColor_t color;          //!< GREEN or AMBER\n} nvmlLedState_t;\n\n/** \n * Static S-class unit info.\n */\ntypedef struct nvmlUnitInfo_st \n{\n    char name[96];                      //!< Product name\n    char id[96];                        //!< Product identifier\n    char serial[96];                    //!< Product serial number\n    char firmwareVersion[96];           //!< Firmware version\n} nvmlUnitInfo_t;\n\n/** \n * Power usage information for an S-class unit.\n * The power supply state is a human readable string that equals \"Normal\" or contains\n * a combination of \"Abnormal\" plus one or more of the following:\n *    \n *    - High voltage\n *    - Fan failure\n *    - Heatsink temperature\n *    - Current limit\n *    - Voltage below UV alarm threshold\n *    - Low-voltage\n *    - SI2C remote off command\n *    - MOD_DISABLE input\n *    - Short pin transition \n*/\ntypedef struct nvmlPSUInfo_st \n{\n    char state[256];                 //!< The power supply state\n    unsigned int current;            //!< PSU current (A)\n    unsigned int voltage;            //!< PSU voltage (V)\n    unsigned int power;              //!< PSU power draw (W)\n} nvmlPSUInfo_t;\n\n/** \n * Fan speed reading for a single fan in an S-class unit.\n */\ntypedef struct nvmlUnitFanInfo_st \n{\n    unsigned int speed;              //!< Fan speed (RPM)\n    nvmlFanState_t state;            //!< Flag that indicates whether fan is working properly\n} nvmlUnitFanInfo_t;\n\n/** \n * Fan speed readings for an entire S-class unit.\n */\ntypedef struct nvmlUnitFanSpeeds_st \n{\n    nvmlUnitFanInfo_t fans[24];      //!< Fan speed data for each fan\n    unsigned int count;              //!< Number of fans in unit\n} nvmlUnitFanSpeeds_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @addtogroup nvmlEvents \n *  @{\n */\n/***************************************************************************************************/\n\n/** \n * Handle to an event set\n */\ntypedef struct nvmlEventSet_st* nvmlEventSet_t;\n\n/** @defgroup nvmlEventType Event Types\n * @{\n * Event Types which user can be notified about.\n * See description of particular functions for details.\n *\n * See \\ref nvmlDeviceRegisterEvents and \\ref nvmlDeviceGetSupportedEventTypes to check which devices \n * support each event.\n *\n * Types can be combined with bitwise or operator '|' when passed to \\ref nvmlDeviceRegisterEvents\n */\n//! Event about single bit ECC errors\n/**\n * \\note A corrected texture memory error is not an ECC error, so it does not generate a single bit event\n */\n#define nvmlEventTypeSingleBitEccError     0x0000000000000001LL\n\n//! Event about double bit ECC errors\n/**\n * \\note An uncorrected texture memory error is not an ECC error, so it does not generate a double bit event\n */\n#define nvmlEventTypeDoubleBitEccError     0x0000000000000002LL\n\n//! Event about PState changes\n/**\n *  \\note On Fermi architecture PState changes are also an indicator that GPU is throttling down due to\n *  no work being executed on the GPU, power capping or thermal capping. In a typical situation,\n *  Fermi-based GPU should stay in P0 for the duration of the execution of the compute process.\n */\n#define nvmlEventTypePState                0x0000000000000004LL\n\n//! Event that Xid critical error occurred\n#define nvmlEventTypeXidCriticalError      0x0000000000000008LL\n\n//! Event about clock changes\n/**\n * Kepler only\n */\n#define nvmlEventTypeClock                 0x0000000000000010LL\n\n//! Mask with no events\n#define nvmlEventTypeNone                  0x0000000000000000LL\n//! Mask of all events\n#define nvmlEventTypeAll (nvmlEventTypeNone    \\\n        | nvmlEventTypeSingleBitEccError       \\\n        | nvmlEventTypeDoubleBitEccError       \\\n        | nvmlEventTypePState                  \\\n        | nvmlEventTypeClock                   \\\n        | nvmlEventTypeXidCriticalError        \\\n        )\n/** @} */\n\n/** \n * Information about occurred event\n */\ntypedef struct nvmlEventData_st\n{\n    nvmlDevice_t        device;         //!< Specific device where the event occurred\n    unsigned long long  eventType;      //!< Information about what specific event occurred\n    unsigned long long  eventData;      //!< Stores last XID error for the device in the event of nvmlEventTypeXidCriticalError, \n                                        //  eventData is 0 for any other event. eventData is set as 999 for unknown xid error.\n} nvmlEventData_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @addtogroup nvmlClocksThrottleReasons\n *  @{\n */\n/***************************************************************************************************/\n\n/** Nothing is running on the GPU and the clocks are dropping to Idle state\n * \\note This limiter may be removed in a later release\n */\n#define nvmlClocksThrottleReasonGpuIdle                   0x0000000000000001LL\n\n/** GPU clocks are limited by current setting of applications clocks\n *\n * @see nvmlDeviceSetApplicationsClocks\n * @see nvmlDeviceGetApplicationsClock\n */\n#define nvmlClocksThrottleReasonApplicationsClocksSetting 0x0000000000000002LL\n\n/** \n * @deprecated Renamed to \\ref nvmlClocksThrottleReasonApplicationsClocksSetting \n *             as the name describes the situation more accurately.\n */\n#define nvmlClocksThrottleReasonUserDefinedClocks         nvmlClocksThrottleReasonApplicationsClocksSetting \n\n/** SW Power Scaling algorithm is reducing the clocks below requested clocks \n *\n * @see nvmlDeviceGetPowerUsage\n * @see nvmlDeviceSetPowerManagementLimit\n * @see nvmlDeviceGetPowerManagementLimit\n */\n#define nvmlClocksThrottleReasonSwPowerCap                0x0000000000000004LL\n\n/** HW Slowdown (reducing the core clocks by a factor of 2 or more) is engaged\n * \n * This is an indicator of:\n *   - temperature being too high\n *   - External Power Brake Assertion is triggered (e.g. by the system power supply)\n *   - Power draw is too high and Fast Trigger protection is reducing the clocks\n *   - May be also reported during PState or clock change\n *      - This behavior may be removed in a later release.\n *\n * @see nvmlDeviceGetTemperature\n * @see nvmlDeviceGetTemperatureThreshold\n * @see nvmlDeviceGetPowerUsage\n */\n#define nvmlClocksThrottleReasonHwSlowdown                0x0000000000000008LL\n\n/** Sync Boost\n *\n * This GPU has been added to a Sync boost group with nvidia-smi or DCGM in\n * order to maximize performance per watt. All GPUs in the sync boost group\n * will boost to the minimum possible clocks across the entire group. Look at\n * the throttle reasons for other GPUs in the system to see why those GPUs are\n * holding this one at lower clocks.\n *\n */\n#define nvmlClocksThrottleReasonSyncBoost                 0x0000000000000010LL\n\n/** SW Thermal Slowdown\n *\n * This is an indicator of one or more of the following:\n *  - Current GPU temperature above the GPU Max Operating Temperature\n *  - Current memory temperature above the Memory Max Operating Temperature\n *\n */\n#define nvmlClocksThrottleReasonSwThermalSlowdown         0x0000000000000020LL\n\n/** HW Thermal Slowdown (reducing the core clocks by a factor of 2 or more) is engaged\n * \n * This is an indicator of:\n *   - temperature being too high\n *\n * @see nvmlDeviceGetTemperature\n * @see nvmlDeviceGetTemperatureThreshold\n * @see nvmlDeviceGetPowerUsage\n */\n#define nvmlClocksThrottleReasonHwThermalSlowdown         0x0000000000000040LL\n\n/** HW Power Brake Slowdown (reducing the core clocks by a factor of 2 or more) is engaged\n * \n * This is an indicator of:\n *   - External Power Brake Assertion being triggered (e.g. by the system power supply)\n *\n * @see nvmlDeviceGetTemperature\n * @see nvmlDeviceGetTemperatureThreshold\n * @see nvmlDeviceGetPowerUsage\n */\n#define nvmlClocksThrottleReasonHwPowerBrakeSlowdown      0x0000000000000080LL\n\n/** GPU clocks are limited by current setting of Display clocks\n *\n * @see bug 1997531\n */\n#define nvmlClocksThrottleReasonDisplayClockSetting       0x0000000000000100LL\n\n/** Bit mask representing no clocks throttling\n *\n * Clocks are as high as possible.\n * */\n#define nvmlClocksThrottleReasonNone                      0x0000000000000000LL\n\n/** Bit mask representing all supported clocks throttling reasons \n * New reasons might be added to this list in the future\n */\n#define nvmlClocksThrottleReasonAll (nvmlClocksThrottleReasonNone \\\n      | nvmlClocksThrottleReasonGpuIdle                           \\\n      | nvmlClocksThrottleReasonApplicationsClocksSetting         \\\n      | nvmlClocksThrottleReasonSwPowerCap                        \\\n      | nvmlClocksThrottleReasonHwSlowdown                        \\\n      | nvmlClocksThrottleReasonSyncBoost                         \\\n      | nvmlClocksThrottleReasonSwThermalSlowdown                 \\\n      | nvmlClocksThrottleReasonHwThermalSlowdown                 \\\n      | nvmlClocksThrottleReasonHwPowerBrakeSlowdown              \\\n      | nvmlClocksThrottleReasonDisplayClockSetting               \\\n)\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlAccountingStats Accounting Statistics\n *  @{\n *\n *  Set of APIs designed to provide per process information about usage of GPU.\n *\n *  @note All accounting statistics and accounting mode live in nvidia driver and reset \n *        to default (Disabled) when driver unloads.\n *        It is advised to run with persistence mode enabled.\n *\n *  @note Enabling accounting mode has no negative impact on the GPU performance.\n */\n/***************************************************************************************************/\n\n/**\n * Describes accounting statistics of a process.\n */\ntypedef struct nvmlAccountingStats_st {\n    unsigned int gpuUtilization;                //!< Percent of time over the process's lifetime during which one or more kernels was executing on the GPU.\n                                                //! Utilization stats just like returned by \\ref nvmlDeviceGetUtilizationRates but for the life time of a\n                                                //! process (not just the last sample period).\n                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlDeviceGetUtilizationRates is not supported\n    \n    unsigned int memoryUtilization;             //!< Percent of time over the process's lifetime during which global (device) memory was being read or written.\n                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlDeviceGetUtilizationRates is not supported\n    \n    unsigned long long maxMemoryUsage;          //!< Maximum total memory in bytes that was ever allocated by the process.\n                                                //! Set to NVML_VALUE_NOT_AVAILABLE if nvmlProcessInfo_t->usedGpuMemory is not supported\n    \n\n    unsigned long long time;                    //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if \n                                                //!< the process is not terminated\n    \n    unsigned long long startTime;               //!< CPU Timestamp in usec representing start time for the process\n    \n    unsigned int isRunning;                     //!< Flag to represent if the process is running (1 for running, 0 for terminated)\n\n    unsigned int reserved[5];                   //!< Reserved for future use\n} nvmlAccountingStats_t;\n\n/** @} */\n\n/***************************************************************************************************/\n\n/***************************************************************************************************/\n/** @defgroup nvmlEncoderStructs Encoder Structs\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Represents type of encoder for capacity can be queried\n */\ntypedef enum nvmlEncoderQueryType_enum\n{\n    NVML_ENCODER_QUERY_H264 = 0,        //!< H264 encoder\n    NVML_ENCODER_QUERY_HEVC = 1,        //!< HEVC encoder\n}nvmlEncoderType_t;\n\n/**\n * Structure to hold encoder session data\n */\ntypedef struct nvmlEncoderSessionInfo_st\n{\n    unsigned int       sessionId;       //!< Unique session ID\n    unsigned int       pid;             //!< Owning process ID\n    nvmlVgpuInstance_t vgpuInstance;    //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero)\n    nvmlEncoderType_t  codecType;       //!< Video encoder type\n    unsigned int       hResolution;     //!< Current encode horizontal resolution\n    unsigned int       vResolution;     //!< Current encode vertical resolution\n    unsigned int       averageFps;      //!< Moving average encode frames per second\n    unsigned int       averageLatency;  //!< Moving average encode latency in microseconds\n}nvmlEncoderSessionInfo_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlFBCStructs Frame Buffer Capture Structures\n*  @{\n*/\n/***************************************************************************************************/\n\n/**\n * Represents frame buffer capture session type\n */\ntypedef enum nvmlFBCSessionType_enum\n{\n    NVML_FBC_SESSION_TYPE_UNKNOWN = 0,     //!< Unknwon\n    NVML_FBC_SESSION_TYPE_TOSYS,           //!< ToSys\n    NVML_FBC_SESSION_TYPE_CUDA,            //!< Cuda\n    NVML_FBC_SESSION_TYPE_VID,             //!< Vid\n    NVML_FBC_SESSION_TYPE_HWENC,           //!< HEnc\n} nvmlFBCSessionType_t;\n\n/**\n * Structure to hold frame buffer capture sessions stats\n */\ntypedef struct nvmlFBCStats_st\n{\n    unsigned int      sessionsCount;    //!< Total no of sessions\n    unsigned int      averageFPS;       //!< Moving average new frames captured per second\n    unsigned int      averageLatency;   //!< Moving average new frame capture latency in microseconds\n} nvmlFBCStats_t;\n\n#define NVML_NVFBC_SESSION_FLAG_DIFFMAP_ENABLED                0x00000001    //!< Bit specifying differential map state.\n#define NVML_NVFBC_SESSION_FLAG_CLASSIFICATIONMAP_ENABLED      0x00000002    //!< Bit specifying classification map state.\n#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_NO_WAIT      0x00000004    //!< Bit specifying if capture was requested as non-blocking call.\n#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_INFINITE     0x00000008    //!< Bit specifying if capture was requested as blocking call.\n#define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_TIMEOUT      0x00000010    //!< Bit specifying if capture was requested as blocking call with timeout period.\n\n/**\n * Structure to hold FBC session data\n */\ntypedef struct nvmlFBCSessionInfo_st\n{\n    unsigned int          sessionId;                           //!< Unique session ID\n    unsigned int          pid;                                 //!< Owning process ID\n    nvmlVgpuInstance_t    vgpuInstance;                        //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero)\n    unsigned int          displayOrdinal;                      //!< Display identifier\n    nvmlFBCSessionType_t  sessionType;                         //!< Type of frame buffer capture session\n    unsigned int          sessionFlags;                        //!< Session flags (one or more of NVML_NVFBC_SESSION_FLAG_XXX).\n    unsigned int          hMaxResolution;                      //!< Max horizontal resolution supported by the capture session\n    unsigned int          vMaxResolution;                      //!< Max vertical resolution supported by the capture session\n    unsigned int          hResolution;                         //!< Horizontal resolution requested by caller in capture call\n    unsigned int          vResolution;                         //!< Vertical resolution requested by caller in capture call\n    unsigned int          averageFPS;                          //!< Moving average new frames captured per second\n    unsigned int          averageLatency;                      //!< Moving average new frame capture latency in microseconds\n} nvmlFBCSessionInfo_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlDrainDefs definitions related to the drain state\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n *  Is the GPU device to be removed from the kernel by nvmlDeviceRemoveGpu()\n */\ntypedef enum nvmlDetachGpuState_enum\n{\n    NVML_DETACH_GPU_KEEP         = 0,\n    NVML_DETACH_GPU_REMOVE,\n} nvmlDetachGpuState_t;\n\n/**\n *  Parent bridge PCIe link state requested by nvmlDeviceRemoveGpu()\n */\ntypedef enum nvmlPcieLinkState_enum\n{\n    NVML_PCIE_LINK_KEEP         = 0,\n    NVML_PCIE_LINK_SHUT_DOWN,\n} nvmlPcieLinkState_t;\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlInitializationAndCleanup Initialization and Cleanup\n * This chapter describes the methods that handle NVML initialization and cleanup.\n * It is the user's responsibility to call \\ref nvmlInit() before calling any other methods, and \n * nvmlShutdown() once NVML is no longer being used.\n *  @{\n */\n/***************************************************************************************************/\n\n#define NVML_INIT_FLAG_NO_GPUS      1   //!< Don't fail nvmlInit() when no GPUs are found\n#define NVML_INIT_FLAG_NO_ATTACH    2   //!< Don't attach GPUs\n\n/**\n * Initialize NVML, but don't initialize any GPUs yet.\n *\n * \\note nvmlInit_v3 introduces a \"flags\" argument, that allows passing boolean values\n *       modifying the behaviour of nvmlInit().\n * \\note In NVML 5.319 new nvmlInit_v2 has replaced nvmlInit\"_v1\" (default in NVML 4.304 and older) that\n *       did initialize all GPU devices in the system.\n *       \n * This allows NVML to communicate with a GPU\n * when other GPUs in the system are unstable or in a bad state.  When using this API, GPUs are\n * discovered and initialized in nvmlDeviceGetHandleBy* functions instead.\n * \n * \\note To contrast nvmlInit_v2 with nvmlInit\"_v1\", NVML 4.304 nvmlInit\"_v1\" will fail when any detected GPU is in\n *       a bad or unstable state.\n * \n * For all products.\n *\n * This method, should be called once before invoking any other methods in the library.\n * A reference count of the number of initializations is maintained.  Shutdown only occurs\n * when the reference count reaches zero.\n * \n * @return \n *         - \\ref NVML_SUCCESS                   if NVML has been properly initialized\n *         - \\ref NVML_ERROR_DRIVER_NOT_LOADED   if NVIDIA driver is not running\n *         - \\ref NVML_ERROR_NO_PERMISSION       if NVML does not have permission to talk to the driver\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlInit(void);\n\n/**\n * nvmlInitWithFlags is a variant of nvmlInit(), that allows passing a set of boolean values\n *       modifying the behaviour of nvmlInit().\n *       Other than the \"flags\" parameter it is completely similar to \\ref nvmlInit.\n *       \n * For all products.\n *\n * @param flags                                 behaviour modifier flags\n *\n * @return \n *         - \\ref NVML_SUCCESS                   if NVML has been properly initialized\n *         - \\ref NVML_ERROR_DRIVER_NOT_LOADED   if NVIDIA driver is not running\n *         - \\ref NVML_ERROR_NO_PERMISSION       if NVML does not have permission to talk to the driver\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlInitWithFlags(unsigned int flags);\n\n/**\n * Shut down NVML by releasing all GPU resources previously allocated with \\ref nvmlInit().\n * \n * For all products.\n *\n * This method should be called after NVML work is done, once for each call to \\ref nvmlInit()\n * A reference count of the number of initializations is maintained.  Shutdown only occurs\n * when the reference count reaches zero.  For backwards compatibility, no error is reported if\n * nvmlShutdown() is called more times than nvmlInit().\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if NVML has been properly shut down\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlShutdown(void);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlErrorReporting Error reporting\n * This chapter describes helper functions for error reporting routines.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Helper method for converting NVML error codes into readable strings.\n *\n * For all products.\n *\n * @param result                               NVML error code to convert\n *\n * @return String representation of the error.\n *\n */\nconst DECLDIR char* nvmlErrorString(nvmlReturn_t result);\n/** @} */\n\n\n/***************************************************************************************************/\n/** @defgroup nvmlConstants Constants\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetInforomVersion and \\ref nvmlDeviceGetInforomImageVersion\n */\n#define NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE       16\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetUUID\n */\n#define NVML_DEVICE_UUID_BUFFER_SIZE                  80\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetBoardPartNumber\n */\n#define NVML_DEVICE_PART_NUMBER_BUFFER_SIZE           80\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlSystemGetDriverVersion\n */\n#define NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE        80\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlSystemGetNVMLVersion\n */\n#define NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE          80\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetName\n */\n#define NVML_DEVICE_NAME_BUFFER_SIZE                  64\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetSerial\n */\n#define NVML_DEVICE_SERIAL_BUFFER_SIZE                30\n\n/**\n * Buffer size guaranteed to be large enough for \\ref nvmlDeviceGetVbiosVersion\n */\n#define NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE         32\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlSystemQueries System Queries\n * This chapter describes the queries that NVML can perform against the local system. These queries\n * are not device-specific.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Retrieves the version of the system's graphics driver.\n * \n * For all products.\n *\n * The version identifier is an alphanumeric string.  It will not exceed 80 characters in length\n * (including the NULL terminator).  See \\ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE.\n *\n * @param version                              Reference in which to return the version identifier\n * @param length                               The maximum allowed length of the string returned in \\a version\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a version is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n */\nnvmlReturn_t DECLDIR nvmlSystemGetDriverVersion(char *version, unsigned int length);\n\n/**\n * Retrieves the version of the NVML library.\n * \n * For all products.\n *\n * The version identifier is an alphanumeric string.  It will not exceed 80 characters in length\n * (including the NULL terminator).  See \\ref nvmlConstants::NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE.\n *\n * @param version                              Reference in which to return the version identifier\n * @param length                               The maximum allowed length of the string returned in \\a version\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a version is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n */\nnvmlReturn_t DECLDIR nvmlSystemGetNVMLVersion(char *version, unsigned int length);\n\n/**\n * Retrieves the version of the CUDA driver.\n *\n * For all products.\n *\n * The CUDA driver version returned will be retreived from the currently installed version of CUDA.\n * If the cuda library is not found, this function will return a known supported version number.\n *\n * @param cudaDriverVersion                    Reference in which to return the version identifier\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a cudaDriverVersion has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a cudaDriverVersion is NULL\n */\nnvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion(int *cudaDriverVersion);\n\n/**\n * Retrieves the version of the CUDA driver from the shared library.\n *\n * For all products.\n *\n * The returned CUDA driver version by calling cuDriverGetVersion()\n *\n * @param cudaDriverVersion                    Reference in which to return the version identifier\n *\n * @return\n *         - \\ref NVML_SUCCESS                  if \\a cudaDriverVersion has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a cudaDriverVersion is NULL\n *         - \\ref NVML_ERROR_LIBRARY_NOT_FOUND  if \\a libcuda.so.1 or libcuda.dll is not found\n *         - \\ref NVML_ERROR_FUNCTION_NOT_FOUND if \\a cuDriverGetVersion() is not found in the shared library\n */\nnvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion_v2(int *cudaDriverVersion);\n\n/**\n * Macros for converting the CUDA driver version number to Major and Minor version numbers.\n */\n#define NVML_CUDA_DRIVER_VERSION_MAJOR(v) ((v)/1000)\n#define NVML_CUDA_DRIVER_VERSION_MINOR(v) (((v)%1000)/10)\n\n/**\n * Gets name of the process with provided process id\n *\n * For all products.\n *\n * Returned process name is cropped to provided length.\n * name string is encoded in ANSI.\n *\n * @param pid                                  The identifier of the process\n * @param name                                 Reference in which to return the process name\n * @param length                               The maximum allowed length of the string returned in \\a name\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a name has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a name is NULL or \\a length is 0.\n *         - \\ref NVML_ERROR_NOT_FOUND         if process doesn't exists\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlSystemGetProcessName(unsigned int pid, char *name, unsigned int length);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlUnitQueries Unit Queries\n * This chapter describes that queries that NVML can perform against each unit. For S-class systems only.\n * In each case the device is identified with an nvmlUnit_t handle. This handle is obtained by \n * calling \\ref nvmlUnitGetHandleByIndex().\n *  @{\n */\n/***************************************************************************************************/\n\n /**\n * Retrieves the number of units in the system.\n *\n * For S-class products.\n *\n * @param unitCount                            Reference in which to return the number of units\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a unitCount has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unitCount is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetCount(unsigned int *unitCount);\n\n/**\n * Acquire the handle for a particular unit, based on its index.\n *\n * For S-class products.\n *\n * Valid indices are derived from the \\a unitCount returned by \\ref nvmlUnitGetCount(). \n *   For example, if \\a unitCount is 2 the valid indices are 0 and 1, corresponding to UNIT 0 and UNIT 1.\n *\n * The order in which NVML enumerates units has no guarantees of consistency between reboots.\n *\n * @param index                                The index of the target unit, >= 0 and < \\a unitCount\n * @param unit                                 Reference in which to return the unit handle\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a unit has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a index is invalid or \\a unit is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit);\n\n/**\n * Retrieves the static information associated with a unit.\n *\n * For S-class products.\n *\n * See \\ref nvmlUnitInfo_t for details on available unit info.\n *\n * @param unit                                 The identifier of the target unit\n * @param info                                 Reference in which to return the unit information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a info has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit is invalid or \\a info is NULL\n */\nnvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info);\n\n/**\n * Retrieves the LED state associated with this unit.\n *\n * For S-class products.\n *\n * See \\ref nvmlLedState_t for details on allowed states.\n *\n * @param unit                                 The identifier of the target unit\n * @param state                                Reference in which to return the current LED state\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a state has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit is invalid or \\a state is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlUnitSetLedState()\n */\nnvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state);\n\n/**\n * Retrieves the PSU stats for the unit.\n *\n * For S-class products.\n *\n * See \\ref nvmlPSUInfo_t for details on available PSU info.\n *\n * @param unit                                 The identifier of the target unit\n * @param psu                                  Reference in which to return the PSU information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a psu has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit is invalid or \\a psu is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu);\n\n/**\n * Retrieves the temperature readings for the unit, in degrees C.\n *\n * For S-class products.\n *\n * Depending on the product, readings may be available for intake (type=0), \n * exhaust (type=1) and board (type=2).\n *\n * @param unit                                 The identifier of the target unit\n * @param type                                 The type of reading to take\n * @param temp                                 Reference in which to return the intake temperature\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a temp has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit or \\a type is invalid or \\a temp is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp);\n\n/**\n * Retrieves the fan speed readings for the unit.\n *\n * For S-class products.\n *\n * See \\ref nvmlUnitFanSpeeds_t for details on available fan speed info.\n *\n * @param unit                                 The identifier of the target unit\n * @param fanSpeeds                            Reference in which to return the fan speed information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a fanSpeeds has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit is invalid or \\a fanSpeeds is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds);\n\n/**\n * Retrieves the set of GPU devices that are attached to the specified unit.\n *\n * For S-class products.\n *\n * The \\a deviceCount argument is expected to be set to the size of the input \\a devices array.\n *\n * @param unit                                 The identifier of the target unit\n * @param deviceCount                          Reference in which to provide the \\a devices array size, and\n *                                             to return the number of attached GPU devices\n * @param devices                              Reference in which to return the references to the attached GPU devices\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a deviceCount and \\a devices have been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a deviceCount indicates that the \\a devices array is too small\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit is invalid, either of \\a deviceCount or \\a devices is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices);\n\n/**\n * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system.\n * \n * For S-class products.\n *\n * The \\a hwbcCount argument is expected to be set to the size of the input \\a hwbcEntries array.\n * The HIC must be connected to an S-class system for it to be reported by this function.\n *\n * @param hwbcCount                            Size of hwbcEntries array\n * @param hwbcEntries                          Array holding information about hwbc\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a hwbcCount and \\a hwbcEntries have been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if either \\a hwbcCount or \\a hwbcEntries is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a hwbcCount indicates that the \\a hwbcEntries array is too small\n */\nnvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries);\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlDeviceQueries Device Queries\n * This chapter describes that queries that NVML can perform against each device.\n * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by  \n * calling one of \\ref nvmlDeviceGetHandleByIndex(), \\ref nvmlDeviceGetHandleBySerial(),\n * \\ref nvmlDeviceGetHandleByPciBusId(). or \\ref nvmlDeviceGetHandleByUUID(). \n *  @{\n */\n/***************************************************************************************************/\n\n /**\n * Retrieves the number of compute devices in the system. A compute device is a single GPU.\n * \n * For all products.\n *\n * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system\n *       even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device.\n *       Update your code to handle this error, or use NVML 4.304 or older nvml header file.\n *       For backward binary compatibility reasons _v1 version of the API is still present in the shared\n *       library.\n *       Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to.\n *\n * @param deviceCount                          Reference in which to return the number of accessible devices\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a deviceCount has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a deviceCount is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount);\n\n/**\n * Acquire the handle for a particular device, based on its index.\n * \n * For all products.\n *\n * Valid indices are derived from the \\a accessibleDevices count returned by \n *   \\ref nvmlDeviceGetCount(). For example, if \\a accessibleDevices is 2 the valid indices  \n *   are 0 and 1, corresponding to GPU 0 and GPU 1.\n *\n * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it\n *   is recommended that devices be looked up by their PCI ids or UUID. See \n *   \\ref nvmlDeviceGetHandleByUUID() and \\ref nvmlDeviceGetHandleByPciBusId().\n *\n * Note: The NVML index may not correlate with other APIs, such as the CUDA device index.\n *\n * Starting from NVML 5, this API causes NVML to initialize the target GPU\n * NVML may initialize additional GPUs if:\n *  - The target GPU is an SLI slave\n * \n * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system\n *       even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device.\n *       Update your code to handle this error, or use NVML 4.304 or older nvml header file.\n *       For backward binary compatibility reasons _v1 version of the API is still present in the shared\n *       library.\n *       Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to.\n *\n *       This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index.\n *       If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't\n *       need to worry about that.\n *\n * @param index                                The index of the target GPU, >= 0 and < \\a accessibleDevices\n * @param device                               Reference in which to return the device handle\n * \n * @return \n *         - \\ref NVML_SUCCESS                  if \\a device has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a index is invalid or \\a device is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables\n *         - \\ref NVML_ERROR_NO_PERMISSION      if the user doesn't have permission to talk to this device\n *         - \\ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n *\n * @see nvmlDeviceGetIndex\n * @see nvmlDeviceGetCount\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device);\n\n/**\n * Acquire the handle for a particular device, based on its board serial number.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * This number corresponds to the value printed directly on the board, and to the value returned by\n *   \\ref nvmlDeviceGetSerial().\n *\n * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor \n *             of \\ref nvmlDeviceGetHandleByUUID.\n *             For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT.\n *\n * Starting from NVML 5, this API causes NVML to initialize the target GPU\n * NVML may initialize additional GPUs as it searches for the target GPU\n *\n * @param serial                               The board serial number of the target GPU\n * @param device                               Reference in which to return the device handle\n * \n * @return \n *         - \\ref NVML_SUCCESS                  if \\a device has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a serial is invalid, \\a device is NULL or more than one\n *                                              device has the same serial (dual GPU boards)\n *         - \\ref NVML_ERROR_NOT_FOUND          if \\a serial does not match a valid device on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables\n *         - \\ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if any GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n *\n * @see nvmlDeviceGetSerial\n * @see nvmlDeviceGetHandleByUUID\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device);\n\n/**\n * Acquire the handle for a particular device, based on its globally unique immutable UUID associated with each device.\n *\n * For all products.\n *\n * @param uuid                                 The UUID of the target GPU\n * @param device                               Reference in which to return the device handle\n * \n * Starting from NVML 5, this API causes NVML to initialize the target GPU\n * NVML may initialize additional GPUs as it searches for the target GPU\n *\n * @return \n *         - \\ref NVML_SUCCESS                  if \\a device has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a uuid is invalid or \\a device is null\n *         - \\ref NVML_ERROR_NOT_FOUND          if \\a uuid does not match a valid device on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables\n *         - \\ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if any GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n *\n * @see nvmlDeviceGetUUID\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device);\n\n/**\n * Acquire the handle for a particular device, based on its PCI bus id.\n * \n * For all products.\n *\n * This value corresponds to the nvmlPciInfo_t::busId returned by \\ref nvmlDeviceGetPciInfo().\n *\n * Starting from NVML 5, this API causes NVML to initialize the target GPU\n * NVML may initialize additional GPUs if:\n *  - The target GPU is an SLI slave\n *\n * \\note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId\"_v1\" returns NVML_ERROR_NOT_FOUND \n *       instead of NVML_ERROR_NO_PERMISSION.\n *\n * @param pciBusId                             The PCI bus id of the target GPU\n * @param device                               Reference in which to return the device handle\n * \n * @return \n *         - \\ref NVML_SUCCESS                  if \\a device has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a pciBusId is invalid or \\a device is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND          if \\a pciBusId does not match a valid device on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables\n *         - \\ref NVML_ERROR_NO_PERMISSION      if the user doesn't have permission to talk to this device\n *         - \\ref NVML_ERROR_IRQ_ISSUE          if NVIDIA kernel detected an interrupt issue with the attached GPUs\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device);\n\n/**\n * Retrieves the name of this device. \n * \n * For all products.\n *\n * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not\n * exceed 64 characters in length (including the NULL terminator).  See \\ref\n * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.\n *\n * @param device                               The identifier of the target device\n * @param name                                 Reference in which to return the product name\n * @param length                               The maximum allowed length of the string returned in \\a name\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a name has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a name is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length);\n\n/**\n * Retrieves the brand of this device.\n *\n * For all products.\n *\n * The type is a member of \\ref nvmlBrandType_t defined above.\n *\n * @param device                               The identifier of the target device\n * @param type                                 Reference in which to return the product brand type\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a name has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a type is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type);\n\n/**\n * Retrieves the NVML index of this device.\n *\n * For all products.\n * \n * Valid indices are derived from the \\a accessibleDevices count returned by \n *   \\ref nvmlDeviceGetCount(). For example, if \\a accessibleDevices is 2 the valid indices  \n *   are 0 and 1, corresponding to GPU 0 and GPU 1.\n *\n * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it\n *   is recommended that devices be looked up by their PCI ids or GPU UUID. See \n *   \\ref nvmlDeviceGetHandleByPciBusId() and \\ref nvmlDeviceGetHandleByUUID().\n *\n * Note: The NVML index may not correlate with other APIs, such as the CUDA device index.\n *\n * @param device                               The identifier of the target device\n * @param index                                Reference in which to return the NVML index of the device\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a index has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a index is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetHandleByIndex()\n * @see nvmlDeviceGetCount()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index);\n\n/**\n * Retrieves the globally unique board serial number associated with this device's board.\n *\n * For all products with an inforom.\n *\n * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator).\n * This number matches the serial number tag that is physically attached to the board.  See \\ref\n * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE.\n *\n * @param device                               The identifier of the target device\n * @param serial                               Reference in which to return the board/module serial number\n * @param length                               The maximum allowed length of the string returned in \\a serial\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a serial has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a serial is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length);\n\n/**\n * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device\n * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2,\n *     result[0] = 0x3, result[1] = 0x3\n *\n * For Kepler &tm; or newer fully supported devices.\n * Supported on Linux only.\n *\n * @param device                               The identifier of the target device\n * @param cpuSetSize                           The size of the cpuSet array that is safe to access\n * @param cpuSet                               Array reference in which to return a bitmask of CPUs, 64 CPUs per \n *                                                 unsigned long on 64-bit machines, 32 on 32-bit machines\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a cpuAffinity has been filled\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, cpuSetSize == 0, or cpuSet is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet);\n\n/**\n * Sets the ideal affinity for the calling thread and device using the guidelines \n * given in nvmlDeviceGetCpuAffinity().  Note, this is a change as of version 8.0.  \n * Older versions set the affinity for a calling process and all children.\n * Currently supports up to 64 processors.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Supported on Linux only.\n *\n * @param device                               The identifier of the target device\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the calling process has been successfully bound\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device);\n\n/**\n * Clear all affinity bindings for the calling thread.  Note, this is a change as of version\n * 8.0 as older versions cleared the affinity for a calling process and all children.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Supported on Linux only.\n *\n * @param device                               The identifier of the target device\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the calling process has been successfully unbound\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device);\n\n/**\n * Retrieve the common ancestor for two devices\n * For all products.\n * Supported on Linux only.\n *\n * @param device1                              The identifier of the first device\n * @param device2                              The identifier of the second device\n * @param pathInfo                             A \\ref nvmlGpuTopologyLevel_t that gives the path type\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a pathInfo has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device1, or \\a device2 is invalid, or \\a pathInfo is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo);\n\n/**\n * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level\n * For all products.\n * Supported on Linux only.\n *\n * @param device                               The identifier of the first device\n * @param level                                The \\ref nvmlGpuTopologyLevel_t level to search for other GPUs\n * @param count                                When zero, is set to the number of matching GPUs such that \\a deviceArray \n *                                             can be malloc'd.  When non-zero, \\a deviceArray will be filled with \\a count\n *                                             number of device handles.\n * @param deviceArray                          An array of device handles for GPUs found at \\a level\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a deviceArray or \\a count (if initially zero) has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a level, or \\a count is invalid, or \\a deviceArray is NULL with a non-zero \\a count\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray);\n\n/**\n * Retrieve the set of GPUs that have a CPU affinity with the given CPU number\n * For all products.\n * Supported on Linux only.\n *\n * @param cpuNumber                            The CPU number\n * @param count                                When zero, is set to the number of matching GPUs such that \\a deviceArray \n *                                             can be malloc'd.  When non-zero, \\a deviceArray will be filled with \\a count\n *                                             number of device handles.\n * @param deviceArray                          An array of device handles for GPUs found with affinity to \\a cpuNumber\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a deviceArray or \\a count (if initially zero) has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a cpuNumber, or \\a count is invalid, or \\a deviceArray is NULL with a non-zero \\a count\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device or OS does not support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           an error has occurred in underlying topology discovery\n */\nnvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray);\n\n/**\n * Retrieve the status for a given p2p capability index between a given pair of GPU \n * \n * @param device1                              The first device \n * @param device2                              The second device\n * @param p2pIndex                             p2p Capability Index being looked for between \\a device1 and \\a device2\n * @param p2pStatus                            Reference in which to return the status of the \\a p2pIndex\n *                                             between \\a device1 and \\a device2\n * @return \n *         - \\ref NVML_SUCCESS         if \\a p2pStatus has been populated\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT     if \\a device1 or \\a device2 or \\a p2pIndex is invalid or \\a p2pStatus is NULL\n *         - \\ref NVML_ERROR_UNKNOWN              on any unexpected error\n */ \nnvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus);\n\n/**\n * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string,\n * that augments the immutable, board serial identifier.\n *\n * For all products.\n *\n * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products.\n * It does NOT correspond to any identifier printed on the board.  It will not exceed 80 characters in length\n * (including the NULL terminator).  See \\ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.\n *\n * @param device                               The identifier of the target device\n * @param uuid                                 Reference in which to return the GPU UUID\n * @param length                               The maximum allowed length of the string returned in \\a uuid\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a uuid has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a uuid is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length);\n\n/**\n * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for \n * each GPU will have the form /dev/nvidia[minor number].\n *\n * For all products.\n * Supported only for Linux\n *\n * @param device                                The identifier of the target device\n * @param minorNumber                           Reference in which to return the minor number for the device\n * @return\n *         - \\ref NVML_SUCCESS                 if the minor number is successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a minorNumber is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber);\n\n/**\n * Retrieves the the device board part number which is programmed into the board's InfoROM\n *\n * For all products.\n *\n * @param device                                Identifier of the target device\n * @param partNumber                            Reference to the buffer to return\n * @param length                                Length of the buffer reference\n *\n * @return\n *         - \\ref NVML_SUCCESS                  if \\a partNumber has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_NOT_SUPPORTED      if the needed VBIOS fields have not been filled\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a device is invalid or \\a serial is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length);\n\n/**\n * Retrieves the version information for the device's infoROM object.\n *\n * For all products with an inforom.\n *\n * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate \n * ECC counts. The version of the data structures in this memory may change from time to time. It will not\n * exceed 16 characters in length (including the NULL terminator).\n * See \\ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE.\n *\n * See \\ref nvmlInforomObject_t for details on the available infoROM objects.\n *\n * @param device                               The identifier of the target device\n * @param object                               The target infoROM object\n * @param version                              Reference in which to return the infoROM version\n * @param length                               The maximum allowed length of the string returned in \\a version\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a version is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not have an infoROM\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetInforomImageVersion\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length);\n\n/**\n * Retrieves the global infoROM image version\n *\n * For all products with an inforom.\n *\n * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board \n * in contrast to infoROM object version which is only an indicator of supported features.\n * Version string will not exceed 16 characters in length (including the NULL terminator).\n * See \\ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE.\n *\n * @param device                               The identifier of the target device\n * @param version                              Reference in which to return the infoROM image version\n * @param length                               The maximum allowed length of the string returned in \\a version\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a version is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not have an infoROM\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetInforomVersion\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length);\n\n/**\n * Retrieves the checksum of the configuration stored in the device's infoROM.\n *\n * For all products with an inforom.\n *\n * Can be used to make sure that two GPUs have the exact same configuration.\n * Current checksum takes into account configuration stored in PWR and ECC infoROM objects.\n * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC)\n *\n * @param device                               The identifier of the target device\n * @param checksum                             Reference in which to return the infoROM configuration checksum\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a checksum has been set\n *         - \\ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a checksum is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error \n */\nnvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum);\n\n/**\n * Reads the infoROM from the flash and verifies the checksums.\n *\n * For all products with an inforom.\n *\n * @param device                               The identifier of the target device\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if infoROM is not corrupted\n *         - \\ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error \n */\nnvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device);\n\n/**\n * Retrieves the display mode for the device.\n *\n * For all products.\n *\n * This method indicates whether a physical display (e.g. monitor) is currently connected to\n * any of the device's connectors.\n *\n * See \\ref nvmlEnableState_t for details on allowed modes.\n *\n * @param device                               The identifier of the target device\n * @param display                              Reference in which to return the display mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a display has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a display is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display);\n\n/**\n * Retrieves the display active state for the device.\n *\n * For all products.\n *\n * This method indicates whether a display is initialized on the device.\n * For example whether X Server is attached to this device and has allocated memory for the screen.\n *\n * Display can be active even when no monitor is physically attached.\n *\n * See \\ref nvmlEnableState_t for details on allowed modes.\n *\n * @param device                               The identifier of the target device\n * @param isActive                             Reference in which to return the display active state\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a isActive has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a isActive is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive);\n\n/**\n * Retrieves the persistence mode associated with this device.\n *\n * For all products.\n * For Linux only.\n *\n * When driver persistence mode is enabled the driver software state is not torn down when the last \n * client disconnects. By default this feature is disabled. \n *\n * See \\ref nvmlEnableState_t for details on allowed modes.\n *\n * @param device                               The identifier of the target device\n * @param mode                                 Reference in which to return the current driver persistence mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a mode has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetPersistenceMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode);\n\n/**\n * Retrieves the PCI attributes of this device.\n * \n * For all products.\n *\n * See \\ref nvmlPciInfo_t for details on the available PCI info.\n *\n * @param device                               The identifier of the target device\n * @param pci                                  Reference in which to return the PCI info\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a pci has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a pci is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci);\n\n/**\n * Retrieves the maximum PCIe link generation possible with this device and system\n *\n * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will\n * report is generation 1.\n * \n * For Fermi &tm; or newer fully supported devices.\n * \n * @param device                               The identifier of the target device\n * @param maxLinkGen                           Reference in which to return the max PCIe link generation\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a maxLinkGen has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a maxLinkGen is null\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen);\n\n/**\n * Retrieves the maximum PCIe link width possible with this device and system\n *\n * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report\n * a max link width of 8.\n * \n * For Fermi &tm; or newer fully supported devices.\n * \n * @param device                               The identifier of the target device\n * @param maxLinkWidth                         Reference in which to return the max PCIe link generation\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a maxLinkWidth has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a maxLinkWidth is null\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth);\n\n/**\n * Retrieves the current PCIe link generation\n * \n * For Fermi &tm; or newer fully supported devices.\n * \n * @param device                               The identifier of the target device\n * @param currLinkGen                          Reference in which to return the current PCIe link generation\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a currLinkGen has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a currLinkGen is null\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen);\n\n/**\n * Retrieves the current PCIe link width\n * \n * For Fermi &tm; or newer fully supported devices.\n * \n * @param device                               The identifier of the target device\n * @param currLinkWidth                        Reference in which to return the current PCIe link generation\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a currLinkWidth has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a currLinkWidth is null\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if PCIe link information is not available\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth);\n\n/**\n * Retrieve PCIe utilization information.\n * This function is querying a byte counter over a 20ms interval and thus is the \n *   PCIe throughput over that interval.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * This method is not supported in virtual machines running virtual GPU (vGPU).\n *\n * @param device                               The identifier of the target device\n * @param counter                              The specific counter that should be queried \\ref nvmlPcieUtilCounter_t\n * @param value                                Reference in which to return throughput in KB/s\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a value has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a counter is invalid, or \\a value is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value);\n\n/**  \n * Retrieve the PCIe replay counter.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param value                                Reference in which to return the counter's value\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a value has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a value is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value);\n\n/**\n * Retrieves the current clock speeds for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * See \\ref nvmlClockType_t for details on available clock information.\n *\n * @param device                               The identifier of the target device\n * @param type                                 Identify which clock domain to query\n * @param clock                                Reference in which to return the clock speed in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a clock has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clock is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device cannot report the specified clock\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock);\n\n/**\n * Retrieves the maximum clock speeds for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * See \\ref nvmlClockType_t for details on available clock information.\n *\n * \\note On GPUs from Fermi family current P0 clocks (reported by \\ref nvmlDeviceGetClockInfo) can differ from max clocks\n *       by few MHz.\n *\n * @param device                               The identifier of the target device\n * @param type                                 Identify which clock domain to query\n * @param clock                                Reference in which to return the clock speed in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a clock has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clock is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device cannot report the specified clock\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock);\n\n/**\n * Retrieves the current setting of a clock that applications will use unless an overspec situation occurs.\n * Can be changed using \\ref nvmlDeviceSetApplicationsClocks.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param clockType                            Identify which clock domain to query\n * @param clockMHz                             Reference in which to return the clock in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a clockMHz has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clockMHz is NULL or \\a clockType is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);\n\n/**\n * Retrieves the default applications clock that GPU boots with or \n * defaults to after \\ref nvmlDeviceResetApplicationsClocks call.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param clockType                            Identify which clock domain to query\n * @param clockMHz                             Reference in which to return the default clock in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a clockMHz has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clockMHz is NULL or \\a clockType is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * \\see nvmlDeviceGetApplicationsClock\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);\n\n/**\n * Resets the application clock to the default value\n *\n * This is the applications clock that will be used after system reboot or driver reload.\n * Default value is constant, but the current value an be changed using \\ref nvmlDeviceSetApplicationsClocks.\n *\n * On Pascal and newer hardware, if clocks were previously locked with \\ref nvmlDeviceSetApplicationsClocks,\n * this call will unlock clocks. This returns clocks their default behavior ofautomatically boosting above\n * base clocks as thermal limits allow.\n *\n * @see nvmlDeviceGetApplicationsClock\n * @see nvmlDeviceSetApplicationsClocks\n *\n * For Fermi &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.\n *\n * @param device                               The identifier of the target device\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if new settings were successfully set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device);\n\n/**\n * Retrieves the clock speed for the clock specified by the clock type and clock ID.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param clockType                            Identify which clock domain to query\n * @param clockId                              Identify which clock in the domain to query\n * @param clockMHz                             Reference in which to return the clock in MHz\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a clockMHz has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clockMHz is NULL or \\a clockType is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz);\n\n/**\n * Retrieves the customer defined maximum boost clock speed specified by the given clock type.\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param clockType                            Identify which clock domain to query\n * @param clockMHz                             Reference in which to return the clock in MHz\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a clockMHz has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clockMHz is NULL or \\a clockType is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device or the \\a clockType on this device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz);\n\n/**\n * Retrieves the list of possible memory clocks that can be used as an argument for \\ref nvmlDeviceSetApplicationsClocks.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param count                                Reference in which to provide the \\a clocksMHz array size, and\n *                                             to return the number of elements\n * @param clocksMHz                            Reference in which to return the clock in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a count and \\a clocksMHz have been populated \n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a count is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a count is too small (\\a count is set to the number of\n *                                                required elements)\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetApplicationsClocks\n * @see nvmlDeviceGetSupportedGraphicsClocks\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz);\n\n/**\n * Retrieves the list of possible graphics clocks that can be used as an argument for \\ref nvmlDeviceSetApplicationsClocks.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param memoryClockMHz                       Memory clock for which to return possible graphics clocks\n * @param count                                Reference in which to provide the \\a clocksMHz array size, and\n *                                             to return the number of elements\n * @param clocksMHz                            Reference in which to return the clocks in MHz\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a count and \\a clocksMHz have been populated \n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_NOT_FOUND         if the specified \\a memoryClockMHz is not a supported frequency\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clock is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a count is too small \n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetApplicationsClocks\n * @see nvmlDeviceGetSupportedMemoryClocks\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz);\n\n/**\n * Retrieve the current state of Auto Boosted clocks on a device and store it in \\a isEnabled\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates\n * to maximize performance as thermal limits allow.\n *\n * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks.\n * Use \\ref nvmlDeviceSetApplicationsClocks and \\ref nvmlDeviceResetApplicationsClocks to control Auto Boost\n * behavior.\n *\n * @param device                               The identifier of the target device\n * @param isEnabled                            Where to store the current state of Auto Boosted clocks of the target device\n * @param defaultIsEnabled                     Where to store the default Auto Boosted clocks behavior of the target device that the device will\n *                                                 revert to when no applications are using the GPU\n *\n * @return\n *         - \\ref NVML_SUCCESS                 If \\a isEnabled has been been set with the Auto Boosted clocks state of \\a device\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a isEnabled is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled);\n\n/**\n * Try to set the current state of Auto Boosted clocks on a device.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates\n * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock\n * rates are desired.\n *\n * Non-root users may use this API by default but can be restricted by root from using this API by calling\n * \\ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS.\n * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled.\n *\n * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks.\n * Use \\ref nvmlDeviceSetApplicationsClocks and \\ref nvmlDeviceResetApplicationsClocks to control Auto Boost\n * behavior.\n *\n * @param device                               The identifier of the target device\n * @param enabled                              What state to try to set Auto Boosted clocks of the target device to\n *\n * @return\n *         - \\ref NVML_SUCCESS                 If the Auto Boosted clocks were successfully set to the state specified by \\a enabled\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled);\n\n/**\n * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will\n * return to when no compute running processes (e.g. CUDA application which have an active context) are running\n *\n * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.\n * Requires root/admin permissions.\n *\n * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates\n * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock\n * rates are desired.\n *\n * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks.\n * Use \\ref nvmlDeviceSetApplicationsClocks and \\ref nvmlDeviceResetApplicationsClocks to control Auto Boost\n * behavior.\n *\n * @param device                               The identifier of the target device\n * @param enabled                              What state to try to set default Auto Boosted clocks of the target device to\n * @param flags                                Flags that change the default behavior. Currently Unused.\n *\n * @return\n *         - \\ref NVML_SUCCESS                 If the Auto Boosted clock's default state was successfully set to the state specified by \\a enabled\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_NO_PERMISSION     If the calling user does not have permission to change Auto Boosted clock's default state.\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support Auto Boosted clocks\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags);\n\n\n/**\n * Retrieves the intended operating speed of the device's fan.\n *\n * Note: The reported speed is the intended fan speed.  If the fan is physically blocked and unable to spin, the\n * output will not match the actual fan speed.\n * \n * For all discrete products with dedicated fans.\n *\n * The fan speed is expressed as a percent of the maximum, i.e. full speed is 100%.\n *\n * @param device                               The identifier of the target device\n * @param speed                                Reference in which to return the fan speed percentage\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a speed has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a speed is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not have a fan\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed);\n\n\n/**\n * Retrieves the intended operating speed of the device's specified fan.\n *\n * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the\n * output will not match the actual fan speed.\n *\n * For all discrete products with dedicated fans.\n *\n * The fan speed is expressed as a percentage of the maximum, i.e. full speed is 100%\n *\n * @param device                                The identifier of the target device\n * @param fan                                   The index of the target fan, zero indexed.\n * @param speed                                 Reference in which to return the fan speed percentage\n *\n * @return\n *        - \\ref NVML_SUCCESS                   if \\a speed has been set\n *        - \\ref NVML_ERROR_UNINITIALIZED       if the library has not been successfully initialized\n *        - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a device is invalid, \\a fan is not an acceptable index, or \\a speed is NULL\n *        - \\ref NVML_ERROR_NOT_SUPPORTED       if the device does not have a fan or is newer than Maxwell\n *        - \\ref NVML_ERROR_GPU_IS_LOST         if the target GPU has fallen off the bus or is otherwise inaccessible\n *        - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int * speed);\n\n\n/**\n * Retrieves the current temperature readings for the device, in degrees C. \n * \n * For all products.\n *\n * See \\ref nvmlTemperatureSensors_t for details on available temperature sensors.\n *\n * @param device                               The identifier of the target device\n * @param sensorType                           Flag that indicates which sensor reading to retrieve\n * @param temp                                 Reference in which to return the temperature reading\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a temp has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a sensorType is invalid or \\a temp is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not have the specified sensor\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp);\n\n/**\n * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * See \\ref nvmlTemperatureThresholds_t for details on available temperature thresholds.\n *\n * @param device                               The identifier of the target device\n * @param thresholdType                        The type of threshold value queried\n * @param temp                                 Reference in which to return the temperature reading\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a temp has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a thresholdType is invalid or \\a temp is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not have a temperature sensor or is unsupported\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp);\n\n/**\n * Retrieves the current performance state for the device. \n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * See \\ref nvmlPstates_t for details on allowed performance states.\n *\n * @param device                               The identifier of the target device\n * @param pState                               Reference in which to return the performance state reading\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a pState has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a pState is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState);\n\n/**\n * Retrieves current clocks throttling reasons.\n *\n * For all fully supported products.\n *\n * \\note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once.\n *\n * @param device                                The identifier of the target device\n * @param clocksThrottleReasons                 Reference in which to return bitmask of active clocks throttle\n *                                                  reasons\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a clocksThrottleReasons has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a clocksThrottleReasons is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlClocksThrottleReasons\n * @see nvmlDeviceGetSupportedClocksThrottleReasons\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons);\n\n/**\n * Retrieves bitmask of supported clocks throttle reasons that can be returned by \n * \\ref nvmlDeviceGetCurrentClocksThrottleReasons\n *\n * For all fully supported products.\n *\n * This method is not supported in virtual machines running virtual GPU (vGPU).\n *\n * @param device                               The identifier of the target device\n * @param supportedClocksThrottleReasons       Reference in which to return bitmask of supported\n *                                              clocks throttle reasons\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a supportedClocksThrottleReasons has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a supportedClocksThrottleReasons is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlClocksThrottleReasons\n * @see nvmlDeviceGetCurrentClocksThrottleReasons\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons);\n\n/**\n * Deprecated: Use \\ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization.\n *\n * Retrieve the current performance state for the device. \n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * See \\ref nvmlPstates_t for details on allowed performance states.\n *\n * @param device                               The identifier of the target device\n * @param pState                               Reference in which to return the performance state reading\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a pState has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a pState is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState);\n\n/**\n * This API has been deprecated.\n *\n * Retrieves the power management mode associated with this device.\n *\n * For products from the Fermi family.\n *     - Requires \\a NVML_INFOROM_POWER version 3.0 or higher.\n *\n * For from the Kepler or newer families.\n *     - Does not require \\a NVML_INFOROM_POWER object.\n *\n * This flag indicates whether any power management algorithm is currently active on the device. An \n * enabled state does not necessarily mean the device is being actively throttled -- only that \n * that the driver will do so if the appropriate conditions are met.\n *\n * See \\ref nvmlEnableState_t for details on allowed modes.\n *\n * @param device                               The identifier of the target device\n * @param mode                                 Reference in which to return the current power management mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a mode has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode);\n\n/**\n * Retrieves the power management limit associated with this device.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * The power limit defines the upper boundary for the card's power draw. If\n * the card's total power draw reaches this limit the power management algorithm kicks in.\n *\n * This reading is only available if power management mode is supported. \n * See \\ref nvmlDeviceGetPowerManagementMode.\n *\n * @param device                               The identifier of the target device\n * @param limit                                Reference in which to return the power management limit in milliwatts\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a limit has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a limit is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit);\n\n/**\n * Retrieves information about possible values of power management limits on this device.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param minLimit                             Reference in which to return the minimum power management limit in milliwatts\n * @param maxLimit                             Reference in which to return the maximum power management limit in milliwatts\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a minLimit and \\a maxLimit have been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a minLimit or \\a maxLimit is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetPowerManagementLimit\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit);\n\n/**\n * Retrieves default power management limit on this device, in milliwatts.\n * Default power management limit is a power management limit that the device boots with.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param defaultLimit                         Reference in which to return the default power management limit in milliwatts\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a defaultLimit has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a defaultLimit is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit);\n\n/**\n * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory)\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw.\n *\n * It is only available if power management mode is supported. See \\ref nvmlDeviceGetPowerManagementMode.\n *\n * @param device                               The identifier of the target device\n * @param power                                Reference in which to return the power usage information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a power has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a power is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support power readings\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power);\n\n/**\n * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded\n *\n * For newer than Pascal &tm; fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param energy                               Reference in which to return the energy consumption information\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a energy has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a energy is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support energy readings\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy);\n\n/**\n * Get the effective power limit that the driver enforces after taking into account all limiters\n *\n * Note: This can be different from the \\ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere\n * This includes the out of band power limit interface\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                           The device to communicate with\n * @param limit                            Reference in which to return the power management limit in milliwatts\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a limit has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a limit is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit);\n\n/**\n * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot).\n *\n * For GK110 M-class and X-class Tesla &tm; products from the Kepler family.\n * Modes \\ref NVML_GOM_LOW_DP and \\ref NVML_GOM_ALL_ON are supported on fully supported GeForce products.\n * Not supported on Quadro &reg; and Tesla &tm; C-class products.\n *\n * @param device                               The identifier of the target device\n * @param current                              Reference in which to return the current GOM\n * @param pending                              Reference in which to return the pending GOM\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a mode has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a current or \\a pending is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlGpuOperationMode_t\n * @see nvmlDeviceSetGpuOperationMode\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending);\n\n/**\n * Retrieves the amount of used, free and total memory available on the device, in bytes.\n * \n * For all products.\n *\n * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits.\n * Under WDDM most device memory is allocated and managed on startup by Windows.\n *\n * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated \n * by all active channels on the device.\n *\n * See \\ref nvmlMemory_t for details on available memory info.\n *\n * @param device                               The identifier of the target device\n * @param memory                               Reference in which to return the memory information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a memory has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a memory is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory);\n\n/**\n * Retrieves the current compute mode for the device.\n *\n * For all products.\n *\n * See \\ref nvmlComputeMode_t for details on allowed compute modes.\n *\n * @param device                               The identifier of the target device\n * @param mode                                 Reference in which to return the current compute mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a mode has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetComputeMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode);\n\n/**\n * Retrieves the CUDA compute capability of the device.\n *\n * For all products.\n *\n * Returns the major and minor compute capability version numbers of the\n * device.  The major and minor versions are equivalent to the\n * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and\n * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be\n * returned by CUDA's cuDeviceGetAttribute().\n *\n * @param device                               The identifier of the target device\n * @param major                                Reference in which to return the major CUDA compute capability\n * @param minor                                Reference in which to return the minor CUDA compute capability\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a major and \\a minor have been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a major or \\a minor are NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor);\n\n/**\n * Retrieves the current and pending ECC modes for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n * Only applicable to devices with ECC.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher.\n *\n * Changing ECC modes requires a reboot. The \"pending\" ECC mode refers to the target mode following\n * the next reboot.\n *\n * See \\ref nvmlEnableState_t for details on allowed modes.\n *\n * @param device                               The identifier of the target device\n * @param current                              Reference in which to return the current ECC mode\n * @param pending                              Reference in which to return the pending ECC mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a current and \\a pending have been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or either \\a current or \\a pending is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceSetEccMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending);\n\n/**\n * Retrieves the device boardId from 0-N.\n * Devices with the same boardId indicate GPUs connected to the same PLX.  Use in conjunction with \n *  \\ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well.\n *  The boardId returned is a unique ID for the current configuration.  Uniqueness and ordering across \n *  reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and\n *  the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will \n *  always return those values but they will always be different from each other).\n *  \n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param boardId                              Reference in which to return the device's board ID\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a boardId has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a boardId is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId);\n\n/**\n * Retrieves whether the device is on a Multi-GPU Board\n * Devices that are on multi-GPU boards will set \\a multiGpuBool to a non-zero value.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param multiGpuBool                         Reference in which to return a zero or non-zero value\n *                                                 to indicate whether the device is on a multi GPU board\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a multiGpuBool has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a multiGpuBool is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool);\n\n/**\n * Retrieves the total ECC error counts for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n * Only applicable to devices with ECC.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher.\n * Requires ECC Mode to be enabled.\n *\n * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of \n * errors across the entire device.\n *\n * See \\ref nvmlMemoryErrorType_t for a description of available error types.\\n\n * See \\ref nvmlEccCounterType_t for a description of available counter types.\n *\n * @param device                               The identifier of the target device\n * @param errorType                            Flag that specifies the type of the errors. \n * @param counterType                          Flag that specifies the counter-type of the errors. \n * @param eccCounts                            Reference in which to return the specified ECC errors\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a eccCounts has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a errorType or \\a counterType is invalid, or \\a eccCounts is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceClearEccErrorCounts()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts);\n\n/**\n * Retrieves the detailed ECC error counts for the device.\n *\n * @deprecated   This API supports only a fixed set of ECC error locations\n *               On different GPU architectures different locations are supported\n *               See \\ref nvmlDeviceGetMemoryErrorCounter\n *\n * For Fermi &tm; or newer fully supported devices.\n * Only applicable to devices with ECC.\n * Requires \\a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts.\n * Requires ECC Mode to be enabled.\n *\n * Detailed errors provide separate ECC counts for specific parts of the memory system.\n *\n * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported.\n *\n * See \\ref nvmlMemoryErrorType_t for a description of available bit types.\\n\n * See \\ref nvmlEccCounterType_t for a description of available counter types.\\n\n * See \\ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts.\n *\n * @param device                               The identifier of the target device\n * @param errorType                            Flag that specifies the type of the errors. \n * @param counterType                          Flag that specifies the counter-type of the errors. \n * @param eccCounts                            Reference in which to return the specified ECC errors\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a eccCounts has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a errorType or \\a counterType is invalid, or \\a eccCounts is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceClearEccErrorCounts()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts);\n\n/**\n * Retrieves the requested memory error counter for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n * Requires \\a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts.\n *\n * Only applicable to devices with ECC.\n *\n * Requires ECC Mode to be enabled.\n *\n * See \\ref nvmlMemoryErrorType_t for a description of available memory error types.\\n\n * See \\ref nvmlEccCounterType_t for a description of available counter types.\\n\n * See \\ref nvmlMemoryLocation_t for a description of available counter locations.\\n\n * \n * @param device                               The identifier of the target device\n * @param errorType                            Flag that specifies the type of error.\n * @param counterType                          Flag that specifies the counter-type of the errors. \n * @param locationType                         Specifies the location of the counter. \n * @param count                                Reference in which to return the ECC counter\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a count has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a bitTyp,e \\a counterType or \\a locationType is\n *                                             invalid, or \\a count is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support ECC error reporting in the specified memory\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType,\n                                                   nvmlEccCounterType_t counterType,\n                                                   nvmlMemoryLocation_t locationType, unsigned long long *count);\n\n/**\n * Retrieves the current utilization rates for the device's major subsystems.\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * See \\ref nvmlUtilization_t for details on available utilization rates.\n *\n * \\note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings.\n *       This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization.\n *\n * @param device                               The identifier of the target device\n * @param utilization                          Reference in which to return the utilization information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a utilization has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a utilization is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization);\n\n/**\n * Retrieves the current utilization and sampling size in microseconds for the Encoder\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param utilization                          Reference to an unsigned int for encoder utilization info\n * @param samplingPeriodUs                     Reference to an unsigned int for the sampling period in US\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a utilization has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a utilization is NULL, or \\a samplingPeriodUs is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs);\n\n/**\n * Retrieves the current capacity of the device's encoder, as a percentage of maximum encoder capacity with valid values in the range 0-100.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param encoderQueryType                  Type of encoder to query\n * @param encoderCapacity                   Reference to an unsigned int for the encoder capacity\n * \n * @return\n *         - \\ref NVML_SUCCESS                  if \\a encoderCapacity is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a encoderCapacity is NULL, or \\a device or \\a encoderQueryType\n *                                              are invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED      if device does not support the encoder specified in \\a encodeQueryType\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity);\n\n/**\n * Retrieves the current encoder statistics for a given device.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param sessionCount                      Reference to an unsigned int for count of active encoder sessions\n * @param averageFps                        Reference to an unsigned int for trailing average FPS of all active sessions\n * @param averageLatency                    Reference to an unsigned int for encode latency in microseconds\n * \n * @return\n *         - \\ref NVML_SUCCESS                  if \\a sessionCount, \\a averageFps and \\a averageLatency is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a sessionCount, or \\a device or \\a averageFps,\n *                                              or \\a averageLatency is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount,\n                                                unsigned int *averageFps, unsigned int *averageLatency);\n\n/**\n * Retrieves information about active encoder sessions on a target device.\n *\n * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \\a sessionInfos. The\n * array elememt count is passed in \\a sessionCount, and \\a sessionCount is used to return the number of sessions\n * written to the buffer.\n *\n * If the supplied buffer is not large enough to accomodate the active session array, the function returns\n * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \\a sessionCount.\n * To query the number of active encoder sessions, call this function with *sessionCount = 0.  The code will return\n * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param sessionCount                      Reference to caller supplied array size, and returns the number of sessions.\n * @param sessionInfos                      Reference in which to return the session information\n * \n * @return\n *         - \\ref NVML_SUCCESS                  if \\a sessionInfos is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE  if \\a sessionCount is too small, array element count is returned in \\a sessionCount\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a sessionCount is NULL.\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos);\n\n/**\n * Retrieves the current utilization and sampling size in microseconds for the Decoder\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param utilization                          Reference to an unsigned int for decoder utilization info\n * @param samplingPeriodUs                     Reference to an unsigned int for the sampling period in US\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a utilization has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a utilization is NULL, or \\a samplingPeriodUs is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs);\n\n/**\n* Retrieves the active frame buffer capture sessions statistics for a given device.\n*\n* For Maxwell &tm; or newer fully supported devices.\n*\n* @param device                            The identifier of the target device\n* @param fbcStats                          Reference to nvmlFBCStats_t structure contianing NvFBC stats\n*\n* @return\n*         - \\ref NVML_SUCCESS                  if \\a fbcStats is fetched\n*         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n*         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a fbcStats is NULL\n*         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n*         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n*/\nnvmlReturn_t DECLDIR nvmlDeviceGetFBCStats(nvmlDevice_t device, nvmlFBCStats_t *fbcStats);\n\n/**\n* Retrieves information about active frame buffer capture sessions on a target device.\n*\n* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \\a sessionInfo. The\n* array element count is passed in \\a sessionCount, and \\a sessionCount is used to return the number of sessions\n* written to the buffer.\n*\n* If the supplied buffer is not large enough to accomodate the active session array, the function returns\n* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \\a sessionCount.\n* To query the number of active FBC sessions, call this function with *sessionCount = 0.  The code will return\n* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount.\n*\n* For Maxwell &tm; or newer fully supported devices.\n*\n* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \\a sessionInfo may\n*       be zero if there are no new frames captured since the session started.\n*\n* @param device                            The identifier of the target device\n* @param sessionCount                      Reference to caller supplied array size, and returns the number of sessions.\n* @param sessionInfo                       Reference in which to return the session information\n*\n* @return\n*         - \\ref NVML_SUCCESS                  if \\a sessionInfo is fetched\n*         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n*         - \\ref NVML_ERROR_INSUFFICIENT_SIZE  if \\a sessionCount is too small, array element count is returned in \\a sessionCount\n*         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a sessionCount is NULL.\n*         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n*         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n*/\nnvmlReturn_t DECLDIR nvmlDeviceGetFBCSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo);\n\n/**\n * Retrieves the current and pending driver model for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n * For windows only.\n *\n * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached\n * to the device it must run in WDDM mode. TCC mode is preferred if a display is not attached.\n *\n * See \\ref nvmlDriverModel_t for details on available driver models.\n *\n * @param device                               The identifier of the target device\n * @param current                              Reference in which to return the current driver model\n * @param pending                              Reference in which to return the pending driver model\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if either \\a current and/or \\a pending have been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or both \\a current and \\a pending are NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the platform is not windows\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlDeviceSetDriverModel()\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending);\n\n/**\n * Get VBIOS version of the device.\n *\n * For all products.\n *\n * The VBIOS version may change from time to time. It will not exceed 32 characters in length \n * (including the NULL terminator).  See \\ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE.\n *\n * @param device                               The identifier of the target device\n * @param version                              Reference to which to return the VBIOS version\n * @param length                               The maximum allowed length of the string returned in \\a version\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a version is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small \n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length);\n\n/**\n * Get Bridge Chip Information for all the bridge chips on the board.\n * \n * For all fully supported products.\n * Only applicable to multi-GPU products.\n * \n * @param device                                The identifier of the target device\n * @param bridgeHierarchy                       Reference to the returned bridge chip Hierarchy\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if bridge chip exists\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, or \\a bridgeInfo is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if bridge chip not supported on the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n */\nnvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy);\n\n/**\n * Get information about processes with a compute context on a device\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * This function returns information only about compute running processes (e.g. CUDA application which have\n * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function.\n *\n * To query the current number of running compute processes, call this function with *infoCount = 0. The\n * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call\n * \\a infos is allowed to be NULL.\n *\n * The usedGpuMemory field returned is all of the memory used by the application.\n *\n * Keep in mind that information returned by this call is dynamic and the number of elements might change in\n * time. Allocate more space for \\a infos table in case new compute processes are spawned.\n *\n * @param device                               The identifier of the target device\n * @param infoCount                            Reference in which to provide the \\a infos array size, and\n *                                             to return the number of returned elements\n * @param infos                                Reference in which to return the process information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a infoCount and \\a infos have been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a infoCount indicates that the \\a infos array is too small\n *                                             \\a infoCount will contain minimal amount of space necessary for\n *                                             the call to complete\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, either of \\a infoCount or \\a infos is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see \\ref nvmlSystemGetProcessName\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos);\n\n/**\n * Get information about processes with a graphics context on a device\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * This function returns information only about graphics based processes \n * (eg. applications using OpenGL, DirectX)\n *\n * To query the current number of running graphics processes, call this function with *infoCount = 0. The\n * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call\n * \\a infos is allowed to be NULL.\n *\n * The usedGpuMemory field returned is all of the memory used by the application.\n *\n * Keep in mind that information returned by this call is dynamic and the number of elements might change in\n * time. Allocate more space for \\a infos table in case new graphics processes are spawned.\n *\n * @param device                               The identifier of the target device\n * @param infoCount                            Reference in which to provide the \\a infos array size, and\n *                                             to return the number of returned elements\n * @param infos                                Reference in which to return the process information\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a infoCount and \\a infos have been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a infoCount indicates that the \\a infos array is too small\n *                                             \\a infoCount will contain minimal amount of space necessary for\n *                                             the call to complete\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, either of \\a infoCount or \\a infos is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see \\ref nvmlSystemGetProcessName\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos);\n\n/**\n * Check if the GPU devices are on the same physical board.\n *\n * For all fully supported products.\n *\n * @param device1                               The first GPU device\n * @param device2                               The second GPU device\n * @param onSameBoard                           Reference in which to return the status.\n *                                              Non-zero indicates that the GPUs are on the same board.\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a onSameBoard has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a dev1 or \\a dev2 are invalid or \\a onSameBoard is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this check is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the either GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard);\n\n/**\n * Retrieves the root/admin permissions on the target API. See \\a nvmlRestrictedAPI_t for the list of supported APIs.\n * If an API is restricted only root users can call that API. See \\a nvmlDeviceSetAPIRestriction to change current permissions.\n *\n * For all fully supported products.\n *\n * @param device                               The identifier of the target device\n * @param apiType                              Target API type for this operation\n * @param isRestricted                         Reference in which to return the current restriction \n *                                             NVML_FEATURE_ENABLED indicates that the API is root-only\n *                                             NVML_FEATURE_DISABLED indicates that the API is accessible to all users\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a isRestricted has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a apiType incorrect or \\a isRestricted is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device or the device does not support\n *                                                 the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is\n *                                                 not supported by the device)\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlRestrictedAPI_t\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted);\n\n/**\n * Gets recent samples for the GPU.\n * \n * For Kepler &tm; or newer fully supported devices.\n * \n * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by \n * the driver.\n * \n * Power, Utilization and Clock samples are returned as type \"unsigned int\" for the union nvmlValue_t.\n * \n * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL. \n * The returned samplesCount will provide the number of samples that can be queried. The user needs to \n * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t).\n * \n * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the \n * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query \n * to get more recent samples.\n * \n * This method fetches the number of entries which can be accommodated in the provided samples array, and the \n * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this \n * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost.\n * \n * @param device                        The identifier for the target device\n * @param type                          Type of sampling event\n * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp. \n * @param sampleValType                 Output parameter to represent the type of sample value as described in nvmlSampleVal_t\n * @param sampleCount                   Reference to provide the number of elements which can be queried in samples array\n * @param samples                       Reference in which samples are returned\n \n * @return \n *         - \\ref NVML_SUCCESS                 if samples are successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a samplesCount is NULL or \n *                                             reference to \\a sampleCount is 0 for non null \\a samples\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_NOT_FOUND         if sample entries are not found\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp,\n        nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples);\n\n/**\n * Gets Total, Available and Used size of BAR1 memory.\n * \n * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party \n * devices (peer-to-peer on the PCIE bus). \n * \n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param bar1Memory                           Reference in which BAR1 memory\n *                                             information is returned.\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if BAR1 memory is successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a bar1Memory is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory);\n\n\n/**\n * Gets the duration of time during which the device was throttled (lower than requested clocks) due to power \n * or thermal constraints.\n *\n * The method is important to users who are tying to understand if their GPUs throttle at any point during their applications. The\n * difference in violation times at two different reference times gives the indication of GPU throttling event. \n *\n * Violation for thermal capping is not supported at this time.\n * \n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param perfPolicyType                       Represents Performance policy which can trigger GPU throttling\n * @param violTime                             Reference to which violation time related information is returned \n *                                         \n *\n * @return\n *         - \\ref NVML_SUCCESS                 if violation time is successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a perfPolicyType is invalid, or \\a violTime is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this query is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime);\n\n/**\n * @}\n */\n\n/** @addtogroup nvmlAccountingStats\n *  @{\n */\n\n/**\n * Queries the state of per process accounting mode.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * See \\ref nvmlDeviceGetAccountingStats for more details.\n * See \\ref nvmlDeviceSetAccountingMode\n *\n * @param device                               The identifier of the target device\n * @param mode                                 Reference in which to return the current accounting mode\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the mode has been successfully retrieved \n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode are NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode);\n\n/**\n * Queries process's accounting stats.\n *\n * For Kepler &tm; or newer fully supported devices.\n * \n * Accounting stats capture GPU utilization and other statistics across the lifetime of a process.\n * Accounting stats can be queried during life time of the process and after its termination.\n * The time field in \\ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and \n * updated to actual running time after its termination.\n * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old\n * processes.\n *\n * See \\ref nvmlAccountingStats_t for description of each returned metric.\n * List of processes that can be queried can be retrieved from \\ref nvmlDeviceGetAccountingPids.\n *\n * @note Accounting Mode needs to be on. See \\ref nvmlDeviceGetAccountingMode.\n * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be\n *         queried since they don't contribute to GPU utilization.\n * @note In case of pid collision stats of only the latest process (that terminated last) will be reported\n *\n * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU.\n * \n * @param device                               The identifier of the target device\n * @param pid                                  Process Id of the target process to query stats for\n * @param stats                                Reference in which to return the process's accounting stats\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if stats have been successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a stats are NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if process stats were not found\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetAccountingBufferSize\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats);\n\n/**\n * Queries list of processes that can be queried for accounting stats. The list of processes returned \n * can be in running or terminated state.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * To just query the number of processes ready to be queried, call this function with *count = 0 and\n * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty.\n * \n * For more details see \\ref nvmlDeviceGetAccountingStats.\n *\n * @note In case of PID collision some processes might not be accessible before the circular buffer is full.\n *\n * @param device                               The identifier of the target device\n * @param count                                Reference in which to provide the \\a pids array size, and\n *                                               to return the number of elements ready to be queried\n * @param pids                                 Reference in which to return list of process ids\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if pids were successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a count is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a count is too small (\\a count is set to\n *                                                 expected value)\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetAccountingBufferSize\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids);\n\n/**\n * Returns the number of processes that the circular buffer with accounting pids can hold.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * This is the maximum number of processes that accounting information will be stored for before information\n * about oldest processes will get overwritten by information about new processes.\n *\n * @param device                               The identifier of the target device\n * @param bufferSize                           Reference in which to provide the size (in number of elements)\n *                                               of the circular buffer for accounting stats.\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if buffer size was successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a bufferSize is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature or accounting mode is disabled\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlDeviceGetAccountingStats\n * @see nvmlDeviceGetAccountingPids\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize);\n\n/** @} */\n\n/** @addtogroup nvmlDeviceQueries\n *  @{\n */\n\n/**\n * Returns the list of retired pages by source, including pages that are pending retirement\n * The address information provided from this API is the hardware address of the page that was retired.  Note\n * that this does not match the virtual address used in CUDA, but will match the address information in XID 63\n * \n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param cause                             Filter page addresses by cause of retirement\n * @param pageCount                         Reference in which to provide the \\a addresses buffer size, and\n *                                          to return the number of retired pages that match \\a cause\n *                                          Set to 0 to query the size without allocating an \\a addresses buffer\n * @param addresses                         Buffer to write the page addresses into\n * \n * @return\n *         - \\ref NVML_SUCCESS                 if \\a pageCount was populated and \\a addresses was filled\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a pageCount indicates the buffer is not large enough to store all the\n *                                             matching page addresses.  \\a pageCount is set to the needed size.\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a pageCount is NULL, \\a cause is invalid, or \n *                                             \\a addresses is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause,\n    unsigned int *pageCount, unsigned long long *addresses);\n\n/**\n * Returns the list of retired pages by source, including pages that are pending retirement\n * The address information provided from this API is the hardware address of the page that was retired.  Note\n * that this does not match the virtual address used in CUDA, but will match the address information in XID 63\n *\n * \\note nvmlDeviceGetRetiredPages_v2 adds an additional timestamps paramter to return the time of each page's\n *       retirement.\n * \n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param cause                             Filter page addresses by cause of retirement\n * @param pageCount                         Reference in which to provide the \\a addresses buffer size, and\n *                                          to return the number of retired pages that match \\a cause\n *                                          Set to 0 to query the size without allocating an \\a addresses buffer\n * @param addresses                         Buffer to write the page addresses into\n * @param timestamps                        Buffer to write the timestamps of page retirement, additional for _v2\n * \n * @return\n *         - \\ref NVML_SUCCESS                 if \\a pageCount was populated and \\a addresses was filled\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a pageCount indicates the buffer is not large enough to store all the\n *                                             matching page addresses.  \\a pageCount is set to the needed size.\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a pageCount is NULL, \\a cause is invalid, or \n *                                             \\a addresses is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages_v2(nvmlDevice_t device, nvmlPageRetirementCause_t cause,\n    unsigned int *pageCount, unsigned long long *addresses, unsigned long long *timestamps);\n\n/**\n * Check if any pages are pending retirement and need a reboot to fully retire.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                            The identifier of the target device\n * @param isPending                         Reference in which to return the pending status\n * \n * @return\n *         - \\ref NVML_SUCCESS                 if \\a isPending was populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a isPending is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlUnitCommands Unit Commands\n *  This chapter describes NVML operations that change the state of the unit. For S-class products.\n *  Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION\n *  error code when invoking any of these methods.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Set the LED state for the unit. The LED can be either green (0) or amber (1).\n *\n * For S-class products.\n * Requires root/admin permissions.\n *\n * This operation takes effect immediately.\n * \n *\n * <b>Current S-Class products don't provide unique LEDs for each unit. As such, both front \n * and back LEDs will be toggled in unison regardless of which unit is specified with this command.</b>\n *\n * See \\ref nvmlLedColor_t for available colors.\n *\n * @param unit                                 The identifier of the target unit\n * @param color                                The target LED color\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the LED color has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a unit or \\a color is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if this is not an S-class product\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlUnitGetLedState()\n */\nnvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlDeviceCommands Device Commands\n *  This chapter describes NVML operations that change the state of the device.\n *  Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION\n *  error code when invoking any of these methods.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Set the persistence mode for the device.\n *\n * For all products.\n * For Linux only.\n * Requires root/admin permissions.\n *\n * The persistence mode determines whether the GPU driver software is torn down after the last client\n * exits.\n *\n * This operation takes effect immediately. It is not persistent across reboots. After each reboot the\n * persistence mode is reset to \"Disabled\".\n *\n * See \\ref nvmlEnableState_t for available modes.\n *\n * After calling this API with mode set to NVML_FEATURE_DISABLED on a device that has its own NUMA\n * memory, the given device handle will no longer be valid, and to continue to interact with this\n * device, a new handle should be obtained from one of the nvmlDeviceGetHandleBy*() APIs. This\n * limitation is currently only applicable to devices that have a coherent NVLink connection to\n * system memory.\n *\n * @param device                               The identifier of the target device\n * @param mode                                 The target persistence mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the persistence mode was set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetPersistenceMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode);\n\n/**\n * Set the compute mode for the device.\n *\n * For all products.\n * Requires root/admin permissions.\n *\n * The compute mode determines whether a GPU can be used for compute operations and whether it can\n * be shared across contexts.\n *\n * This operation takes effect immediately. Under Linux it is not persistent across reboots and\n * always resets to \"Default\". Under windows it is persistent.\n *\n * Under windows compute mode may only be set to DEFAULT when running in WDDM\n *\n * See \\ref nvmlComputeMode_t for details on available compute modes.\n *\n * @param device                               The identifier of the target device\n * @param mode                                 The target compute mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the compute mode was set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetComputeMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode);\n\n/**\n * Set the ECC mode for the device.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Only applicable to devices with ECC.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher.\n * Requires root/admin permissions.\n *\n * The ECC mode determines whether the GPU enables its ECC support.\n *\n * This operation takes effect after the next reboot.\n *\n * See \\ref nvmlEnableState_t for details on available modes.\n *\n * @param device                               The identifier of the target device\n * @param ecc                                  The target ECC mode\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the ECC mode was set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a ecc is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetEccMode()\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc);  \n\n/**\n * Clear the ECC error and other memory error counts for the device.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Only applicable to devices with ECC.\n * Requires \\a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts.\n * Requires \\a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts.\n * Requires root/admin permissions.\n * Requires ECC Mode to be enabled.\n *\n * Sets all of the specified ECC counters to 0, including both detailed and total counts.\n *\n * This operation takes effect immediately.\n *\n * See \\ref nvmlMemoryErrorType_t for details on available counter types.\n *\n * @param device                               The identifier of the target device\n * @param counterType                          Flag that indicates which type of errors should be cleared.\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the error counts were cleared\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a counterType is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see \n *      - nvmlDeviceGetDetailedEccErrors()\n *      - nvmlDeviceGetTotalEccErrors()\n */\nnvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType);\n\n/**\n * Set the driver model for the device.\n *\n * For Fermi &tm; or newer fully supported devices.\n * For windows only.\n * Requires root/admin permissions.\n *\n * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached\n * to the device it must run in WDDM mode.  \n *\n * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce).\n * This should only be done if the host is subsequently powered down and the display is detached from the device\n * before the next reboot. \n *\n * This operation takes effect after the next reboot.\n * \n * Windows driver model may only be set to WDDM when running in DEFAULT compute mode.\n *\n * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or \n * will not support it after reboot. See \\ref nvmlDeviceSetGpuOperationMode.\n *\n * See \\ref nvmlDriverModel_t for details on available driver models.\n * See \\ref nvmlFlagDefault and \\ref nvmlFlagForce\n *\n * @param device                               The identifier of the target device\n * @param driverModel                          The target driver model\n * @param flags                                Flags that change the default behavior\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the driver model has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a driverModel is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the platform is not windows or the device does not support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlDeviceGetDriverModel()\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags);\n\n/**\n * Set clocks that device will lock to.\n *\n * Sets the clocks that the device will be running at to the value in the range of minGpuClockMHz to maxGpuClockMHz.\n * Setting this will supercede application clock values and take effect regardless if a cuda app is running.\n * See /ref nvmlDeviceSetApplicationsClocks\n *\n * Can be used as a setting to request constant performance.\n *\n * Requires root/admin permissions.\n *\n * After system reboot or driver reload applications clocks go back to their default value.\n * See \\ref nvmlDeviceResetGpuLockedClocks.\n *\n * For newer than Pascal &tm; fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param minGpuClockMHz                       Requested minimum gpu clock in MHz\n * @param maxGpuClockMHz                       Requested maximum gpu clock in MHz\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if new settings were successfully set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a minGpuClockMHz and \\a maxGpuClockMHz\n *                                                 is not a valid clock combination\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetGpuLockedClocks(nvmlDevice_t device, unsigned int minGpuClockMHz, unsigned int maxGpuClockMHz);\n\n/**\n * Resets the gpu clock to the default value\n *\n * This is the gpu clock that will be used after system reboot or driver reload.\n * Default values are idle clocks, but the current values can be changed using \\ref nvmlDeviceSetApplicationsClocks.\n *\n * @see nvmlDeviceSetGpuLockedClocks\n *\n * For newer than Pascal &tm; fully supported devices.\n *\n * @param device                               The identifier of the target device\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if new settings were successfully set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceResetGpuLockedClocks(nvmlDevice_t device);\n\n/**\n * Set clocks that applications will lock to.\n *\n * Sets the clocks that compute and graphics applications will be running at.\n * e.g. CUDA driver requests these clocks during context creation which means this property\n * defines clocks at which CUDA applications will be running unless some overspec event\n * occurs (e.g. over power, over thermal or external HW brake).\n *\n * Can be used as a setting to request constant performance.\n *\n * On Pascal and newer hardware, this will automatically disable automatic boosting of clocks.\n *\n * On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance should also call\n * \\ref nvmlDeviceSetAutoBoostedClocksEnabled to prevent clocks from automatically boosting\n * above the clock value being set.\n *\n * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices.\n * Requires root/admin permissions.\n *\n * See \\ref nvmlDeviceGetSupportedMemoryClocks and \\ref nvmlDeviceGetSupportedGraphicsClocks\n * for details on how to list available clocks combinations.\n *\n * After system reboot or driver reload applications clocks go back to their default value.\n * See \\ref nvmlDeviceResetApplicationsClocks.\n *\n * @param device                               The identifier of the target device\n * @param memClockMHz                          Requested memory clock in MHz\n * @param graphicsClockMHz                     Requested graphics clock in MHz\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if new settings were successfully set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a memClockMHz and \\a graphicsClockMHz\n *                                                 is not a valid clock combination\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz);\n\n/**\n * Set new power limit of this device.\n * \n * For Kepler &tm; or newer fully supported devices.\n * Requires root/admin permissions.\n *\n * See \\ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values.\n *\n * \\note Limit is not persistent across reboots or driver unloads.\n * Enable persistent mode to prevent driver from unloading when no application is using the device.\n *\n * @param device                               The identifier of the target device\n * @param limit                                Power management limit in milliwatts to set\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a limit has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a defaultLimit is out of range\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlDeviceGetPowerManagementLimitConstraints\n * @see nvmlDeviceGetPowerManagementDefaultLimit\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit);\n\n/**\n * Sets new GOM. See \\a nvmlGpuOperationMode_t for details.\n *\n * For GK110 M-class and X-class Tesla &tm; products from the Kepler family.\n * Modes \\ref NVML_GOM_LOW_DP and \\ref NVML_GOM_ALL_ON are supported on fully supported GeForce products.\n * Not supported on Quadro &reg; and Tesla &tm; C-class products.\n * Requires root/admin permissions.\n * \n * Changing GOMs requires a reboot. \n * The reboot requirement might be removed in the future.\n *\n * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when\n * pending driver model is WDDM is not supported. See \\ref nvmlDeviceSetDriverModel.\n * \n * @param device                               The identifier of the target device\n * @param mode                                 Target GOM\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a mode has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a mode incorrect\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support GOM or specific mode\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlGpuOperationMode_t\n * @see nvmlDeviceGetGpuOperationMode\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode);\n\n/**\n * Changes the root/admin restructions on certain APIs. See \\a nvmlRestrictedAPI_t for the list of supported APIs.\n * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs.\n * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \\a nvmlDeviceGetAPIRestriction\n * to query the current restriction settings.\n * \n * For Kepler &tm; or newer fully supported devices.\n * Requires root/admin permissions.\n *\n * @param device                               The identifier of the target device\n * @param apiType                              Target API type for this operation\n * @param isRestricted                         The target restriction\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a isRestricted has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a apiType incorrect\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support changing API restrictions or the device does not support\n *                                                 the feature that api restrictions are being set for (E.G. Enabling/disabling auto \n *                                                 boosted clocks is not supported by the device)\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlRestrictedAPI_t\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted);\n\n/**\n * @}\n */\n \n/** @addtogroup nvmlAccountingStats\n *  @{\n */\n\n/**\n * Enables or disables per process accounting.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Requires root/admin permissions.\n *\n * @note This setting is not persistent and will default to disabled after driver unloads.\n *       Enable persistence mode to be sure the setting doesn't switch off to disabled.\n * \n * @note Enabling accounting mode has no negative impact on the GPU performance.\n *\n * @note Disabling accounting clears all accounting pids information.\n *\n * See \\ref nvmlDeviceGetAccountingMode\n * See \\ref nvmlDeviceGetAccountingStats\n * See \\ref nvmlDeviceClearAccountingPids\n *\n * @param device                               The identifier of the target device\n * @param mode                                 The target accounting mode\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the new mode has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a mode are invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode);\n\n/**\n * Clears accounting information about all processes that have already terminated.\n *\n * For Kepler &tm; or newer fully supported devices.\n * Requires root/admin permissions.\n *\n * See \\ref nvmlDeviceGetAccountingMode\n * See \\ref nvmlDeviceGetAccountingStats\n * See \\ref nvmlDeviceSetAccountingMode\n *\n * @param device                               The identifier of the target device\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if accounting information has been cleared \n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device are invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the user doesn't have permission to perform this operation\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup NvLink NvLink Methods\n * This chapter describes methods that NVML can perform on NVLINK enabled devices.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Retrieves the state of the device's NvLink for the link specified\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param isActive                             \\a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that\n *                                             the link is active and NVML_FEATURE_DISABLED indicates it \n *                                             is inactive\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a isActive has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a link is invalid or \\a isActive is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive);\n\n/**\n * Retrieves the version of the device's NvLink for the link specified\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param version                              Requested NvLink version\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a link is invalid or \\a version is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version);\n\n/**\n * Retrieves the requested capability from the device's NvLink for the link specified\n * Please refer to the \\a nvmlNvLinkCapability_t structure for the specific caps that can be queried\n * The return value should be treated as a boolean.\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param capability                           Specifies the \\a nvmlNvLinkCapability_t to be queried\n * @param capResult                            A boolean for the queried capability indicating that feature is available\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a capResult has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a link, or \\a capability is invalid or \\a capResult is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link,\n                                                   nvmlNvLinkCapability_t capability, unsigned int *capResult); \n\n/**\n * Retrieves the PCI information for the remote node on a NvLink link \n * Note: pciSubSystemId is not filled in this function and is indeterminate\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param pci                                  \\a nvmlPciInfo_t of the remote node for the specified link                            \n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a pci has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a link is invalid or \\a pci is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci);\n\n/**\n * Retrieves the specified error counter value\n * Please refer to \\a nvmlNvLinkErrorCounter_t for error counters that are available\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param counter                              Specifies the NvLink counter to be queried\n * @param counterValue                         Returned counter value\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a counter has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a link, or \\a counter is invalid or \\a counterValue is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link,\n                                                     nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue);\n\n/**\n * Resets all error counters to zero\n * Please refer to \\a nvmlNvLinkErrorCounter_t for the list of error counters that are reset\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the reset is successful\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device or \\a link is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link);\n\n/**\n * Set the NVLINK utilization counter control information for the specified counter, 0 or 1.\n * Please refer to \\a nvmlNvLinkUtilizationControl_t for the structure definition.  Performs a reset\n * of the counters if the reset parameter is non-zero.\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param counter                              Specifies the counter that should be set (0 or 1).\n * @param link                                 Specifies the NvLink link to be queried\n * @param control                              A reference to the \\a nvmlNvLinkUtilizationControl_t to set\n * @param reset                                Resets the counters on set if non-zero\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the control has been set successfully\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a counter, \\a link, or \\a control is invalid \n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter,\n                                                           nvmlNvLinkUtilizationControl_t *control, unsigned int reset);\n\n/**\n * Get the NVLINK utilization counter control information for the specified counter, 0 or 1.\n * Please refer to \\a nvmlNvLinkUtilizationControl_t for the structure definition\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param counter                              Specifies the counter that should be set (0 or 1).\n * @param link                                 Specifies the NvLink link to be queried\n * @param control                              A reference to the \\a nvmlNvLinkUtilizationControl_t to place information\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the control has been set successfully\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a counter, \\a link, or \\a control is invalid \n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter,\n                                                           nvmlNvLinkUtilizationControl_t *control);\n\n\n/**\n * Retrieve the NVLINK utilization counter based on the current control for a specified counter.\n * In general it is good practice to use \\a nvmlDeviceSetNvLinkUtilizationControl\n *  before reading the utilization counters as they have no default state\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param counter                              Specifies the counter that should be read (0 or 1).\n * @param rxcounter                            Receive counter return value\n * @param txcounter                            Transmit counter return value\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if \\a rxcounter and \\a txcounter have been successfully set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a counter, or \\a link is invalid or \\a rxcounter or \\a txcounter are NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter, \n                                                           unsigned long long *rxcounter, unsigned long long *txcounter);\n\n/**\n * Freeze the NVLINK utilization counters \n * Both the receive and transmit counters are operated on by this function\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be queried\n * @param counter                              Specifies the counter that should be frozen (0 or 1).\n * @param freeze                               NVML_FEATURE_ENABLED = freeze the receive and transmit counters\n *                                             NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if counters were successfully frozen or unfrozen\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a link, \\a counter, or \\a freeze is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, \n                                            unsigned int counter, nvmlEnableState_t freeze);\n\n/**\n * Reset the NVLINK utilization counters \n * Both the receive and transmit counters are operated on by this function\n *\n * For Pascal &tm; or newer fully supported devices.\n *\n * @param device                               The identifier of the target device\n * @param link                                 Specifies the NvLink link to be reset\n * @param counter                              Specifies the counter that should be reset (0 or 1)\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if counters were successfully reset\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device, \\a link, or \\a counter is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlEvents Event Handling Methods\n * This chapter describes methods that NVML can perform against each device to register and wait for \n * some event to occur.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Create an empty set of events.\n * Event set should be freed by \\ref nvmlEventSetFree\n *\n * For Fermi &tm; or newer fully supported devices.\n * @param set                                  Reference in which to return the event handle\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the event has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a set is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlEventSetFree\n */\nnvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set);\n\n/**\n * Starts recording of events on a specified devices and add the events to specified \\ref nvmlEventSet_t\n *\n * For Fermi &tm; or newer fully supported devices.\n * Ecc events are available only on ECC enabled devices (see \\ref nvmlDeviceGetTotalEccErrors)\n * Power capping events are available only on Power Management enabled devices (see \\ref nvmlDeviceGetPowerManagementMode)\n *\n * For Linux only.\n *\n * \\b IMPORTANT: Operations on \\a set are not thread safe\n *\n * This call starts recording of events on specific device.\n * All events that occurred before this call are not recorded.\n * Checking if some event occurred can be done with \\ref nvmlEventSetWait\n *\n * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed.\n * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes\n *     are registered in that case.\n *\n * @param device                               The identifier of the target device\n * @param eventTypes                           Bitmask of \\ref nvmlEventType to record\n * @param set                                  Set to which add new event types\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the event has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a eventTypes is invalid or \\a set is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the platform does not support this feature or some of requested event types\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlEventType\n * @see nvmlDeviceGetSupportedEventTypes\n * @see nvmlEventSetWait\n * @see nvmlEventSetFree\n */\nnvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set);\n\n/**\n * Returns information about events supported on device\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * Events are not supported on Windows. So this function returns an empty mask in \\a eventTypes on Windows.\n *\n * @param device                               The identifier of the target device\n * @param eventTypes                           Reference in which to return bitmask of supported events\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the eventTypes has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a eventType is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlEventType\n * @see nvmlDeviceRegisterEvents\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes);\n\n/**\n * Waits on events and delivers events\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * If some events are ready to be delivered at the time of the call, function returns immediately.\n * If there are no events ready to be delivered, function sleeps till event arrives \n * but not longer than specified timeout. This function in certain conditions can return before\n * specified timeout passes (e.g. when interrupt arrives)\n * \n * In case of xid error, the function returns the most recent xid error type seen by the system. If there are multiple\n * xid errors generated before nvmlEventSetWait is invoked then the last seen xid error type is returned for all\n * xid error events.\n * \n * @param set                                  Reference to set of events to wait on\n * @param data                                 Reference in which to return event data\n * @param timeoutms                            Maximum amount of wait time in milliseconds for registered event\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the data has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a data is NULL\n *         - \\ref NVML_ERROR_TIMEOUT           if no event arrived in specified timeout or interrupt arrived\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if a GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlEventType\n * @see nvmlDeviceRegisterEvents\n */\nnvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms);\n\n/**\n * Releases events in the set\n *\n * For Fermi &tm; or newer fully supported devices.\n *\n * @param set                                  Reference to events to be released \n * \n * @return \n *         - \\ref NVML_SUCCESS                 if the event has been successfully released\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n * \n * @see nvmlDeviceRegisterEvents\n */\nnvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlZPI Drain states \n * This chapter describes methods that NVML can perform against each device to control their drain state\n * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to\n * power on/off GPUs, enable robust reset scenarios, etc.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Modify the drain state of a GPU.  This method forces a GPU to no longer accept new incoming requests.\n * Any new NVML process will no longer see this GPU.  Persistence mode for this GPU must be turned off before\n * this call is made.\n * Must be called as administrator.\n * For Linux only.\n * \n * For Pascal &tm; or newer fully supported devices.\n * Some Kepler devices supported.\n *\n * @param pciInfo                              The PCI address of the GPU drain state to be modified\n * @param newState                             The drain state that should be entered, see \\ref nvmlEnableState_t\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if counters were successfully reset\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a nvmlIndex or \\a newState is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the calling process has insufficient permissions to perform operation\n *         - \\ref NVML_ERROR_IN_USE            if the device has persistence mode turned on\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState);\n\n/**\n * Query the drain state of a GPU.  This method is used to check if a GPU is in a currently draining\n * state.\n * For Linux only.\n * \n * For Pascal &tm; or newer fully supported devices.\n * Some Kepler devices supported.\n *\n * @param pciInfo                              The PCI address of the GPU drain state to be queried\n * @param currentState                         The current drain state for this GPU, see \\ref nvmlEnableState_t\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if counters were successfully reset\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a nvmlIndex or \\a currentState is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState);\n\n/**\n * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver\n * as long as no other processes are attached. If other processes are attached, this call will return\n * NVML_ERROR_IN_USE and the GPU will be returned to its original \"draining\" state. Note: the\n * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called\n * to initiate the draining state is if that process was using, and is still using, a GPU before the \n * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled\n * prior to this call.\n *\n * For long-running NVML processes please note that this will change the enumeration of current GPUs.\n * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2.\n * Also, device handles after the removed GPU will not be valid and must be re-established.\n * Must be run as administrator. \n * For Linux only.\n *\n * For Pascal &tm; or newer fully supported devices.\n * Some Kepler devices supported.\n *\n * @param pciInfo                              The PCI address of the GPU to be removed\n * @param gpuState                             Whether the GPU is to be removed, from the OS\n *                                             see \\ref nvmlDetachGpuState_t\n * @param linkState                            Requested upstream PCIe link state, see \\ref nvmlPcieLinkState_t\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if counters were successfully reset\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a nvmlIndex is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device doesn't support this feature\n *         - \\ref NVML_ERROR_IN_USE            if the device is still in use and cannot be removed\n */\nnvmlReturn_t DECLDIR nvmlDeviceRemoveGpu (nvmlPciInfo_t *pciInfo, nvmlDetachGpuState_t gpuState, nvmlPcieLinkState_t linkState);\n\n/**\n * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that\n * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device.  \n * If all are zeroes then the entire PCI tree will be searched.  Please note that for long-running NVML processes\n * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order.\n *\n * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds\n * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery.\n *\n * Must be run as administrator.\n * For Linux only.\n * \n * For Pascal &tm; or newer fully supported devices.\n * Some Kepler devices supported.\n *\n * @param pciInfo                              The PCI tree to be searched.  Only the domain, bus, and device\n *                                             fields are used in this call.\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if counters were successfully reset\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a pciInfo is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the operating system does not support this feature\n *         - \\ref NVML_ERROR_OPERATING_SYSTEM  if the operating system is denying this feature\n *         - \\ref NVML_ERROR_NO_PERMISSION     if the calling process has insufficient permissions to perform operation\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlFieldValueQueries Field Value Queries\n *  This chapter describes NVML operations that are associated with retrieving Field Values from NVML\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Request values for a list of fields for a device. This API allows multiple fields to be queried at once.\n * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs\n * will be populated from a single call rather than making a driver call for each fieldId.\n *\n * @param device                               The device handle of the GPU to request field values for\n * @param valuesCount                          Number of entries in values that should be retrieved\n * @param values                               Array of \\a valuesCount structures to hold field values.\n *                                             Each value's fieldId must be populated prior to this call\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if any values in \\a values were populated. Note that you must\n *                                             check the nvmlReturn field of each value for each individual\n *                                             status\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid or \\a values is NULL\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values);\n\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup gridVirtual GRID Virtualization Enums, Constants and Structs\n *  @{\n */\n/** @} */\n/***************************************************************************************************/\n\n/***************************************************************************************************/\n/** @defgroup nvmlGridQueries GRID Virtualization APIs\n * This chapter describes operations that are associated with NVIDIA GRID products.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * This method is used to get the virtualization mode corresponding to the GPU.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                    Identifier of the target device\n * @param pVirtualMode              Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_?\n * \n * @return \n *         - \\ref NVML_SUCCESS                  if \\a pVirtualMode is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a device is invalid or \\a pVirtualMode is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode);\n\n/**\n * Queries if SR-IOV host operation is supported on a vGPU supported device.\n *\n * Checks whether SR-IOV host capability is supported by the device and the\n * driver, and indicates device is in SR-IOV mode if both of these conditions\n * are true.\n *\n * @param device                                The identifier of the target device\n * @param pHostVgpuMode                         Reference in which to return the current vGPU mode\n *\n * @return\n *         - \\ref NVML_SUCCESS                  if device's vGPU mode has been successfully retrieved\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a device handle is 0 or \\a pVgpuMode is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED      if \\a device doesn't support this feature.\n *         - \\ref NVML_ERROR_UNKNOWN            if any unexpected error occurred\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetHostVgpuMode(nvmlDevice_t device, nvmlHostVgpuMode_t *pHostVgpuMode);\n\n/**\n * This method is used to set the virtualization mode corresponding to the GPU.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                    Identifier of the target device\n * @param virtualMode               virtualization mode. One of NVML_GPU_VIRTUALIZATION_?\n *\n * @return \n *         - \\ref NVML_SUCCESS                  if \\a pVirtualMode is set\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a device is invalid or \\a pVirtualMode is NULL\n *         - \\ref NVML_ERROR_GPU_IS_LOST        if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_NOT_SUPPORTED      if setting of virtualization mode is not supported.\n *         - \\ref NVML_ERROR_NO_PERMISSION      if setting of virtualization mode is not allowed for this client.\n */\nnvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode);\n\n/**\n * Retrieve the GRID licensable features.\n *\n * Identifies whether the system supports GRID Software Licensing. If it does, return the list of licensable feature(s)\n * and their current license status.\n *\n * @param device                    Identifier of the target device\n * @param pGridLicensableFeatures   Pointer to structure in which GRID licensable features are returned\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if licensable features are successfully retrieved\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a pGridLicensableFeatures is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures);\n\n/**\n * Retrieves the current utilization and process ID\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running.\n * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at\n * by \\a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization\n * during the last sample period. It includes the CPU timestamp at which  the samples were recorded. Individual utilization values\n * are returned as \"unsigned int\" values.\n *\n * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with\n * \\a utilization set to NULL. The caller should allocate a buffer of size\n * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed\n * in \\a utilization, and \\a processSamplesCount set to the number of entries the buffer is sized for.\n *\n * On successful return, the function updates \\a processSamplesCount with the number of process utilization sample\n * structures that were actually written. This may differ from a previously read value as instances are created or\n * destroyed.\n *\n * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0\n * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp\n * to a timeStamp retrieved from a previous query to read utilization since the previous query.\n *\n * @param device                    The identifier of the target device\n * @param utilization               Pointer to caller-supplied buffer in which guest process utilization samples are returned\n * @param processSamplesCount       Pointer to caller-supplied array size, and returns number of processes running\n * @param lastSeenTimeStamp         Return only samples with timestamp greater than lastSeenTimeStamp.\n\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a utilization has been populated\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a utilization is NULL, or \\a samplingPeriodUs is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the device does not support this feature\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization,\n                                              unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlVgpu GRID vGPU Management\n * @{\n *\n * This chapter describes APIs supporting NVIDIA GRID vGPU\n */\n/***************************************************************************************************/\n\n/**\n * Retrieve the supported vGPU types on a physical GPU (device).\n *\n * An array of supported vGPU types for the physical GPU indicated by \\a device is returned in the caller-supplied buffer\n * pointed at by \\a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \\a vgpuCount, and \\a vgpuCount\n * is used to return the number of vGPU types written to the buffer.\n *\n * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns\n * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \\a vgpuCount.\n * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0.\n * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported.\n *\n * @param device                   The identifier of the target device\n * @param vgpuCount                Pointer to caller-supplied array size, and returns number of vGPU types\n * @param vgpuTypeIds              Pointer to caller-supplied array in which to return list of vGPU types\n *\n * @return\n *         - \\ref NVML_SUCCESS                      successful completion\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE      \\a vgpuTypeIds buffer is too small, array element count is returned in \\a vgpuCount\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT       if \\a vgpuCount is NULL or \\a device is invalid\n *         - \\ref NVML_ERROR_NOT_SUPPORTED          if vGPU is not supported by the device\n *         - \\ref NVML_ERROR_UNKNOWN                on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds);\n\n/**\n * Retrieve the currently creatable vGPU types on a physical GPU (device).\n *\n * An array of creatable vGPU types for the physical GPU indicated by \\a device is returned in the caller-supplied buffer\n * pointed at by \\a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \\a vgpuCount, and \\a vgpuCount\n * is used to return the number of vGPU types written to the buffer.\n *\n * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types\n * can concurrently run on a device.  For example, if only one vGPU type is allowed at a time on a device, then the creatable\n * list will be restricted to whatever vGPU type is already running on the device.\n *\n * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns\n * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \\a vgpuCount.\n * To query the number of vGPU types createable for the GPU, call this function with *vgpuCount = 0.\n * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable.\n *\n * @param device                   The identifier of the target device\n * @param vgpuCount                Pointer to caller-supplied array size, and returns number of vGPU types\n * @param vgpuTypeIds              Pointer to caller-supplied array in which to return list of vGPU types\n *\n * @return\n *         - \\ref NVML_SUCCESS                      successful completion\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE      \\a vgpuTypeIds buffer is too small, array element count is returned in \\a vgpuCount\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT       if \\a vgpuCount is NULL\n *         - \\ref NVML_ERROR_NOT_SUPPORTED          if vGPU is not supported by the device\n *         - \\ref NVML_ERROR_UNKNOWN                on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds);\n\n/**\n * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator).\n * See \\ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param vgpuTypeClass            Pointer to string array to return class in\n * @param size                     Size of string\n *\n * @return\n *         - \\ref NVML_SUCCESS                   successful completion\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a vgpuTypeId is invalid, or \\a vgpuTypeClass is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE   if \\a size is too small\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size);\n\n/**\n * Retrieve the vGPU type name.\n *\n * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not\n * exceed 64 characters in length (including the NUL terminator).  See \\ref\n * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param vgpuTypeName             Pointer to buffer to return name\n * @param size                     Size of buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a name is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a size is too small\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size);\n\n/**\n * Retrieve the device ID of a vGPU type.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param deviceID                 Device ID and vendor ID of the device contained in single 32 bit value\n * @param subsystemID              Subsytem ID and subsytem vendor ID of the device contained in single 32 bit value\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a deviceId or \\a subsystemID are NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID);\n\n/**\n * Retrieve the vGPU framebuffer size in bytes.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param fbSize                   Pointer to framebuffer size in bytes\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a fbSize is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize);\n\n/**\n * Retrieve count of vGPU's supported display heads.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param numDisplayHeads          Pointer to number of display heads\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a numDisplayHeads is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads);\n\n/**\n * Retrieve vGPU display head's maximum supported resolution.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param displayIndex             Zero-based index of display head\n * @param xdim                     Pointer to maximum number of pixels in X dimension\n * @param ydim                     Pointer to maximum number of pixels in Y dimension\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a xdim or \\a ydim are NULL, or \\a displayIndex\n *                                             is out of range.\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim);\n\n/**\n * Retrieve license requirements for a vGPU type\n *\n * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form\n * \"<license name>,<version>\", for example \"GRID-Virtual-PC,2.0\". If a vGPU is runnable with* more than one type of license,\n * the licenses are delimited by a semicolon, for example \"GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0\".\n *\n * The total length of the returned string will not exceed 128 characters, including the NUL terminator.\n * See \\ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param vgpuTypeLicenseString    Pointer to buffer to return license info\n * @param size                     Size of \\a vgpuTypeLicenseString buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a vgpuTypeLicenseString is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a size is too small\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size);\n\n/**\n * Retrieve the static frame rate limit value of the vGPU type\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param frameRateLimit           Reference to return the frame rate limit value\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if frame rate limiter is turned off for the vGPU type\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a frameRateLimit is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit);\n\n/**\n * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                   The identifier of the target device\n * @param vgpuTypeId               Handle to vGPU type\n * @param vgpuInstanceCount        Pointer to get the max number of vGPU instances\n *                                 that can be created on a deicve for given vgpuTypeId\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid or is not supported on target device,\n *                                             or \\a vgpuInstanceCount is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount);\n\n/**\n * Retrieve the maximum number of vGPU instances supported per VM for given vGPU type\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuTypeId               Handle to vGPU type\n * @param vgpuInstanceCountPerVm   Pointer to get the max number of vGPU instances supported per VM for given \\a vgpuTypeId\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuTypeId is invalid, or \\a vgpuInstanceCountPerVm is NULL\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstancesPerVm(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCountPerVm);\n\n/**\n * Retrieve the active vGPU instances on a device.\n *\n * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \\a vgpuInstances. The\n * array elememt count is passed in \\a vgpuCount, and \\a vgpuCount is used to return the number of vGPU instances\n * written to the buffer.\n *\n * If the supplied buffer is not large enough to accomodate the vGPU instance array, the function returns\n * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \\a vgpuCount.\n * To query the number of active vGPU instances, call this function with *vgpuCount = 0.  The code will return\n * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param device                   The identifier of the target device\n * @param vgpuCount                Pointer which passes in the array size as well as get\n *                                 back the number of types\n * @param vgpuInstances            Pointer to array in which to return list of vGPU instances\n *\n * @return\n *         - \\ref NVML_SUCCESS                  successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a device is invalid, or \\a vgpuCount is NULL\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE  if \\a size is too small\n *         - \\ref NVML_ERROR_NOT_SUPPORTED      if vGPU is not supported by the device\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances);\n\n/**\n * Retrieve the VM ID associated with a vGPU instance.\n *\n * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator).\n * See \\ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.\n *\n * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \\a vmIdType.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param vmId                     Pointer to caller-supplied buffer to hold VM ID\n * @param size                     Size of buffer in bytes\n * @param vmIdType                 Pointer to hold VM ID type\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vmId or \\a vmIdType is NULL, or \\a vgpuInstance is 0\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a size is too small\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType);\n\n/**\n * Retrieve the UUID of a vGPU instance.\n *\n * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string,\n * not exceeding 80 characters in length (including the NULL terminator).\n * See \\ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param uuid                     Pointer to caller-supplied buffer to hold vGPU UUID\n * @param size                     Size of buffer in bytes\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a uuid is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a size is too small\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size);\n\n/**\n * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU.\n *\n * The version is returned as an alphanumeric string in the caller-supplied buffer \\a version. The length of the version\n * string will not exceed 80 characters in length (including the NUL terminator).\n * See \\ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE.\n *\n * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is\n * returned as \"Unknown\" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the\n * NVIDIA driver is loaded and initialized.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param version                  Caller-supplied buffer to return driver version string\n * @param length                   Size of \\a version buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a version has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a length is too small\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length);\n\n/**\n * Retrieve the framebuffer usage in bytes.\n *\n * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             The identifier of the target instance\n * @param fbUsage                  Pointer to framebuffer usage in bytes\n *\n * @return\n *         - \\ref NVML_SUCCESS                 successful completion\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a fbUsage is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage);\n\n/**\n * Retrieve the current licensing state of the vGPU instance.\n *\n * If the vGPU is currently licensed, \\a licensed is set to 1, otherwise it is set to 0.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param licensed                 Reference to return the licensing status\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a licensed has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a licensed is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed);\n\n/**\n * Retrieve the vGPU type of a vGPU instance.\n *\n * Returns the vGPU type ID of vgpu assigned to the vGPU instance.\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param vgpuTypeId               Reference to return the vgpuTypeId\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a vgpuTypeId has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a vgpuTypeId is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId);\n\n/**\n * Retrieve the frame rate limit set for the vGPU instance.\n *\n * Returns the value of the frame rate limit set for the vGPU instance\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param frameRateLimit           Reference to return the frame rate limit\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a frameRateLimit has been set\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if frame rate limiter is turned off for the vGPU type\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a frameRateLimit is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit);\n\n/**\n * Retrieve the current ECC mode of vGPU instance.\n *\n * @param vgpuInstance            The identifier of the target vGPU instance\n * @param eccMode                 Reference in which to return the current ECC mode\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if the vgpuInstance's ECC mode has been successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a mode is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the vGPU doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetEccMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *eccMode);\n\n/**\n * Retrieve the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param encoderCapacity          Reference to an unsigned int for the encoder capacity\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a encoderCapacity has been retrived\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a encoderQueryType is invalid\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity);\n\n/**\n * Set the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param vgpuInstance             Identifier of the target vGPU instance\n * @param encoderCapacity          Unsigned int for the encoder capacity value\n *\n * @return\n *         - \\ref NVML_SUCCESS                 if \\a encoderCapacity has been set\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a encoderCapacity is out of range of 0-100.\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int  encoderCapacity);\n\n/**\n * Retrieves the current encoder statistics of a vGPU Instance\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param vgpuInstance                      Identifier of the target vGPU instance\n * @param sessionCount                      Reference to an unsigned int for count of active encoder sessions\n * @param averageFps                        Reference to an unsigned int for trailing average FPS of all active sessions\n * @param averageLatency                    Reference to an unsigned int for encode latency in microseconds\n *\n * @return\n *         - \\ref NVML_SUCCESS                  if \\a sessionCount, \\a averageFps and \\a averageLatency is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a sessionCount , or \\a averageFps or \\a averageLatency is NULL\n *                                              or \\a vgpuInstance is 0.\n *         - \\ref NVML_ERROR_NOT_FOUND          if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount,\n                                                     unsigned int *averageFps, unsigned int *averageLatency);\n\n/**\n * Retrieves information about all active encoder sessions on a vGPU Instance.\n *\n * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \\a sessionInfo. The\n * array element count is passed in \\a sessionCount, and \\a sessionCount is used to return the number of sessions\n * written to the buffer.\n *\n * If the supplied buffer is not large enough to accomodate the active session array, the function returns\n * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \\a sessionCount.\n * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return\n * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param vgpuInstance                      Identifier of the target vGPU instance\n * @param sessionCount                      Reference to caller supplied array size, and returns\n *                                          the number of sessions.\n * @param sessionInfo                       Reference to caller supplied array in which the list\n *                                          of session information us returned.\n *\n * @return\n *         - \\ref NVML_SUCCESS                  if \\a sessionInfo is fetched\n *         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE  if \\a sessionCount is too small, array element count is\n                                                returned in \\a sessionCount\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a sessionCount is NULL, or \\a vgpuInstance is 0.\n *         - \\ref NVML_ERROR_NOT_FOUND          if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo);\n\n/**\n* Retrieves the active frame buffer capture sessions statistics of a vGPU Instance\n*\n* For Maxwell &tm; or newer fully supported devices.\n*\n* @param vgpuInstance                      Identifier of the target vGPU instance\n* @param fbcStats                          Reference to nvmlFBCStats_t structure contianing NvFBC stats\n*\n* @return\n*         - \\ref NVML_SUCCESS                  if \\a fbcStats is fetched\n*         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n*         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a vgpuInstance is 0, or \\a fbcStats is NULL\n*         - \\ref NVML_ERROR_NOT_FOUND          if \\a vgpuInstance does not match a valid active vGPU instance on the system\n*         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n*/\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCStats(nvmlVgpuInstance_t vgpuInstance, nvmlFBCStats_t *fbcStats);\n\n/**\n* Retrieves information about active frame buffer capture sessions on a vGPU Instance.\n*\n* An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \\a sessionInfo. The\n* array element count is passed in \\a sessionCount, and \\a sessionCount is used to return the number of sessions\n* written to the buffer.\n*\n* If the supplied buffer is not large enough to accomodate the active session array, the function returns\n* NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \\a sessionCount.\n* To query the number of active FBC sessions, call this function with *sessionCount = 0.  The code will return\n* NVML_SUCCESS with number of active FBC sessions updated in *sessionCount.\n*\n* For Maxwell &tm; or newer fully supported devices.\n*\n* @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \\a sessionInfo may\n*       be zero if there are no new frames captured since the session started.\n*\n* @param vgpuInstance                      Identifier of the target vGPU instance\n* @param sessionCount                      Reference to caller supplied array size, and returns the number of sessions.\n* @param sessionInfo                       Reference in which to return the session information\n*\n* @return\n*         - \\ref NVML_SUCCESS                  if \\a sessionInfo is fetched\n*         - \\ref NVML_ERROR_UNINITIALIZED      if the library has not been successfully initialized\n*         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a vgpuInstance is 0, or \\a sessionCount is NULL.\n*         - \\ref NVML_ERROR_NOT_FOUND          if \\a vgpuInstance does not match a valid active vGPU instance on the system\n*         - \\ref NVML_ERROR_INSUFFICIENT_SIZE  if \\a sessionCount is too small, array element count is returned in \\a sessionCount\n*         - \\ref NVML_ERROR_UNKNOWN            on any unexpected error\n*/\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvml GRID Virtualization Migration\n * This chapter describes operations that are associated with vGPU Migration.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Structure representing range of vGPU versions.\n */\ntypedef struct nvmlVgpuVersion_st\n{\n    unsigned int minVersion; //!< Minimum vGPU version.\n    unsigned int maxVersion; //!< Maximum vGPU version.\n} nvmlVgpuVersion_t;\n\n/**\n * vGPU metadata structure.\n */\ntypedef struct nvmlVgpuMetadata_st\n{\n    unsigned int             version;                                                    //!< Current version of the structure\n    unsigned int             revision;                                                   //!< Current revision of the structure\n    nvmlVgpuGuestInfoState_t guestInfoState;                                             //!< Current state of Guest-dependent fields\n    char                     guestDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in guest\n    char                     hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE];  //!< Version of driver installed in host\n    unsigned int             reserved[6];                                                //!< Reserved for internal use\n    unsigned int             vgpuVirtualizationCaps;                                     //!< vGPU virtualizaion capabilities bitfileld\n    unsigned int             guestVgpuVersion;                                           //!< vGPU version of guest driver\n    unsigned int             opaqueDataSize;                                             //!< Size of opaque data field in bytes\n    char                     opaqueData[4];                                              //!< Opaque data\n} nvmlVgpuMetadata_t;\n\n/**\n * Physical GPU metadata structure\n */\ntypedef struct nvmlVgpuPgpuMetadata_st\n{\n    unsigned int            version;                                                    //!< Current version of the structure\n    unsigned int            revision;                                                   //!< Current revision of the structure\n    char                    hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE];  //!< Host driver version\n    unsigned int            pgpuVirtualizationCaps;                                     //!< Pgpu virtualizaion capabilities bitfileld\n    unsigned int            reserved[5];                                                //!< Reserved for internal use\n    nvmlVgpuVersion_t       hostSupportedVgpuRange;                                     //!< vGPU version range supported by host driver\n    unsigned int            opaqueDataSize;                                             //!< Size of opaque data field in bytes\n    char                    opaqueData[4];                                              //!< Opaque data\n} nvmlVgpuPgpuMetadata_t;\n\n/**\n * vGPU VM compatibility codes\n */\ntypedef enum nvmlVgpuVmCompatibility_enum\n{\n    NVML_VGPU_VM_COMPATIBILITY_NONE         = 0x0,    //!< vGPU is not runnable\n    NVML_VGPU_VM_COMPATIBILITY_COLD         = 0x1,    //!< vGPU is runnable from a cold / powered-off state (ACPI S5)\n    NVML_VGPU_VM_COMPATIBILITY_HIBERNATE    = 0x2,    //!< vGPU is runnable from a hibernated state (ACPI S4)\n    NVML_VGPU_VM_COMPATIBILITY_SLEEP        = 0x4,    //!< vGPU is runnable from a sleeped state (ACPI S3)\n    NVML_VGPU_VM_COMPATIBILITY_LIVE         = 0x8,    //!< vGPU is runnable from a live/paused (ACPI S0)\n} nvmlVgpuVmCompatibility_t;\n\n/**\n *  vGPU-pGPU compatibility limit codes\n */\ntypedef enum nvmlVgpuPgpuCompatibilityLimitCode_enum\n{\n    NVML_VGPU_COMPATIBILITY_LIMIT_NONE          = 0x0,           //!< Compatibility is not limited.\n    NVML_VGPU_COMPATIBILITY_LIMIT_HOST_DRIVER   = 0x1,           //!< ompatibility is limited by host driver version.\n    NVML_VGPU_COMPATIBILITY_LIMIT_GUEST_DRIVER  = 0x2,           //!< Compatibility is limited by guest driver version.\n    NVML_VGPU_COMPATIBILITY_LIMIT_GPU           = 0x4,           //!< Compatibility is limited by GPU hardware.\n    NVML_VGPU_COMPATIBILITY_LIMIT_OTHER         = 0x80000000,    //!< Compatibility is limited by an undefined factor.\n} nvmlVgpuPgpuCompatibilityLimitCode_t;\n\n/**\n * vGPU-pGPU compatibility structure\n */\ntypedef struct nvmlVgpuPgpuCompatibility_st\n{\n    nvmlVgpuVmCompatibility_t               vgpuVmCompatibility;    //!< Compatibility of vGPU VM. See \\ref nvmlVgpuVmCompatibility_t\n    nvmlVgpuPgpuCompatibilityLimitCode_t    compatibilityLimitCode; //!< Limiting factor for vGPU-pGPU compatibility. See \\ref nvmlVgpuPgpuCompatibilityLimitCode_t\n} nvmlVgpuPgpuCompatibility_t;\n\n/**\n * Returns vGPU metadata structure for a running vGPU. The structure contains information about the vGPU and its associated VM\n * such as the currently installed NVIDIA guest driver version, together with host driver version and an opaque data section\n * containing internal state.\n *\n * nvmlVgpuInstanceGetMetadata() may be called at any time for a vGPU instance. Some fields in the returned structure are\n * dependent on information obtained from the guest VM, which may not yet have reached a state where that information\n * is available. The current state of these dependent fields is reflected in the info structure's \\ref nvmlVgpuGuestInfoState_t field.\n *\n * The VMM may choose to read and save the vGPU's VM info as persistent metadata associated with the VM, and provide\n * it to GRID Virtual GPU Manager when creating a vGPU for subsequent instances of the VM.\n *\n * The caller passes in a buffer via \\a vgpuMetadata, with the size of the buffer in \\a bufferSize. If the vGPU Metadata structure\n * is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed\n * in \\a bufferSize.\n *\n * @param vgpuInstance             vGPU instance handle\n * @param vgpuMetadata             Pointer to caller-supplied buffer into which vGPU metadata is written\n * @param bufferSize               Size of vgpuMetadata buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                   vGPU metadata structure was successfully returned\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE   vgpuMetadata buffer is too small, required size is returned in \\a bufferSize\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a bufferSize is NULL or \\a vgpuInstance is 0; if \\a vgpuMetadata is NULL and the value of \\a bufferSize is not 0.\n *         - \\ref NVML_ERROR_NOT_FOUND           if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetMetadata(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuMetadata_t *vgpuMetadata, unsigned int *bufferSize);\n\n/**\n * Returns a vGPU metadata structure for the physical GPU indicated by \\a device. The structure contains information about\n * the GPU and the currently installed NVIDIA host driver version that's controlling it, together with an opaque data section\n * containing internal state.\n *\n * The caller passes in a buffer via \\a pgpuMetadata, with the size of the buffer in \\a bufferSize. If the \\a pgpuMetadata\n * structure is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed\n * in \\a bufferSize.\n *\n * @param device                The identifier of the target device\n * @param pgpuMetadata          Pointer to caller-supplied buffer into which \\a pgpuMetadata is written\n * @param bufferSize            Pointer to size of \\a pgpuMetadata buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                   GPU metadata structure was successfully returned\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE   pgpuMetadata buffer is too small, required size is returned in \\a bufferSize\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a bufferSize is NULL or \\a device is invalid; if \\a pgpuMetadata is NULL and the value of \\a bufferSize is not 0.\n *         - \\ref NVML_ERROR_NOT_SUPPORTED       vGPU is not supported by the system\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetVgpuMetadata(nvmlDevice_t device, nvmlVgpuPgpuMetadata_t *pgpuMetadata, unsigned int *bufferSize);\n\n/**\n * Takes a vGPU instance metadata structure read from \\ref nvmlVgpuInstanceGetMetadata(), and a vGPU metadata structure for a\n * physical GPU read from \\ref nvmlDeviceGetVgpuMetadata(), and returns compatibility information of the vGPU instance and the\n * physical GPU.\n *\n * The caller passes in a buffer via \\a compatibilityInfo, into which a compatibility information structure is written. The\n * structure defines the states in which the vGPU / VM may be booted on the physical GPU. If the vGPU / VM compatibility\n * with the physical GPU is limited, a limit code indicates the factor limiting compability.\n * (see \\ref nvmlVgpuPgpuCompatibilityLimitCode_t for details).\n *\n * Note: vGPU compatibility does not take into account dynamic capacity conditions that may limit a system's ability to\n *       boot a given vGPU or associated VM.\n *\n * @param vgpuMetadata          Pointer to caller-supplied vGPU metadata structure\n * @param pgpuMetadata          Pointer to caller-supplied GPU metadata structure\n * @param compatibilityInfo     Pointer to caller-supplied buffer to hold compatibility info\n *\n * @return\n *         - \\ref NVML_SUCCESS                   vGPU metadata structure was successfully returned\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a vgpuMetadata or \\a pgpuMetadata or \\a bufferSize are NULL\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlGetVgpuCompatibility(nvmlVgpuMetadata_t *vgpuMetadata, nvmlVgpuPgpuMetadata_t *pgpuMetadata, nvmlVgpuPgpuCompatibility_t *compatibilityInfo);\n\n/**\n * Returns the properties of the physical GPU indicated by the device in an ascii-encoded string format.\n *\n * The caller passes in a buffer via \\a pgpuMetadata, with the size of the buffer in \\a bufferSize. If the\n * string is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed\n * in \\a bufferSize.\n *\n * @param device                The identifier of the target device\n * @param pgpuMetadata          Pointer to caller-supplied buffer into which \\a pgpuMetadata is written\n * @param bufferSize            Pointer to size of \\a pgpuMetadata buffer\n *\n * @return\n *         - \\ref NVML_SUCCESS                   GPU metadata structure was successfully returned\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE   \\a pgpuMetadata buffer is too small, required size is returned in \\a bufferSize\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT    if \\a bufferSize is NULL or \\a device is invalid; if \\a pgpuMetadata is NULL and the value of \\a bufferSize is not 0.\n *         - \\ref NVML_ERROR_NOT_SUPPORTED       if vGPU is not supported by the system\n *         - \\ref NVML_ERROR_UNKNOWN             on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetPgpuMetadataString(nvmlDevice_t device, char *pgpuMetadata, unsigned int *bufferSize);\n\n/*\n * Virtual GPU (vGPU) version\n *\n * The NVIDIA vGPU Manager and the guest drivers are tagged with a range of supported vGPU versions. This determines the range of NVIDIA guest driver versions that\n * are compatible for vGPU feature support with a given NVIDIA vGPU Manager. For vGPU feature support, the range of supported versions for the NVIDIA vGPU Manager \n * and the guest driver must overlap. Otherwise, the guest driver fails to load in the VM.\n *\n * When the NVIDIA guest driver loads, either when the VM is booted or when the driver is installed or upgraded, a negotiation occurs between the guest driver\n * and the NVIDIA vGPU Manager to select the highest mutually compatible vGPU version. The negotiated vGPU version stays the same across VM migration.\n */\n\n/**\n * Query the ranges of supported vGPU versions.\n *\n * This function gets the linear range of supported vGPU versions that is preset for the NVIDIA vGPU Manager and the range set by an administrator.\n * If the preset range has not been overridden by \\ref nvmlSetVgpuVersion, both ranges are the same.\n *\n * The caller passes pointers to the following \\ref nvmlVgpuVersion_t structures, into which the NVIDIA vGPU Manager writes the ranges:\n * 1. \\a supported structure that represents the preset range of vGPU versions supported by the NVIDIA vGPU Manager.\n * 2. \\a current structure that represents the range of supported vGPU versions set by an administrator. By default, this range is the same as the preset range.\n *\n * @param supported  Pointer to the structure in which the preset range of vGPU versions supported by the NVIDIA vGPU Manager is written\n * @param current    Pointer to the structure in which the range of supported vGPU versions set by an administrator is written\n *\n * @return\n * - \\ref NVML_SUCCESS                 The vGPU version range structures were successfully obtained.\n * - \\ref NVML_ERROR_NOT_SUPPORTED     The API is not supported.\n * - \\ref NVML_ERROR_INVALID_ARGUMENT  The \\a supported parameter or the \\a current parameter is NULL.\n * - \\ref NVML_ERROR_UNKNOWN           An error occurred while the data was being fetched.\n */\nnvmlReturn_t DECLDIR nvmlGetVgpuVersion(nvmlVgpuVersion_t *supported, nvmlVgpuVersion_t *current);\n\n/**\n * Override the preset range of vGPU versions supported by the NVIDIA vGPU Manager with a range set by an administrator.\n *\n * This function configures the NVIDIA vGPU Manager with a range of supported vGPU versions set by an administrator. This range must be a subset of the\n * preset range that the NVIDIA vGPU Manager supports. The custom range set by an administrator takes precedence over the preset range and is advertised to\n * the guest VM for negotiating the vGPU version. See \\ref nvmlGetVgpuVersion for details of how to query the preset range of versions supported.\n *\n * This function takes a pointer to vGPU version range structure \\ref nvmlVgpuVersion_t as input to override the preset vGPU version range that the NVIDIA vGPU Manager supports.\n *\n * After host system reboot or driver reload, the range of supported versions reverts to the range that is preset for the NVIDIA vGPU Manager.\n *\n * @note 1. The range set by the administrator must be a subset of the preset range that the NVIDIA vGPU Manager supports. Otherwise, an error is returned.\n *       2. If the range of supported guest driver versions does not overlap the range set by the administrator, the guest driver fails to load.\n *       3. If the range of supported guest driver versions overlaps the range set by the administrator, the guest driver will load with a negotiated \n *          vGPU version that is the maximum value in the overlapping range.\n *       4. No VMs must be running on the host when this function is called. If a VM is running on the host, the call to this function fails.\n *\n * @param vgpuVersion   Pointer to a caller-supplied range of supported vGPU versions.\n *\n * @return\n * - \\ref NVML_SUCCESS                 The preset range of supported vGPU versions was successfully overridden.\n * - \\ref NVML_ERROR_NOT_SUPPORTED     The API is not supported.\n * - \\ref NVML_ERROR_IN_USE            The range was not overridden because a VM is running on the host.\n * - \\ref NVML_ERROR_INVALID_ARGUMENT  The \\a vgpuVersion parameter specifies a range that is outside the range supported by the NVIDIA vGPU Manager or if \\a vgpuVersion is NULL.\n */\nnvmlReturn_t DECLDIR nvmlSetVgpuVersion(nvmlVgpuVersion_t *vgpuVersion);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlUtil GRID Virtualization Utilization and Accounting \n * This chapter describes operations that are associated with vGPU Utilization and Accounting.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Retrieves current utilization for vGPUs on a physical GPU (device).\n *\n * For Kepler &tm; or newer fully supported devices.\n *\n * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running\n * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer\n * pointed at by \\a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the\n * CPU timestamp at which the samples were recorded. Individual utilization values are returned as \"unsigned int\" values\n * in nvmlValue_t unions. The function sets the caller-supplied \\a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to\n * indicate the returned value type.\n *\n * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with\n * \\a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance\n * count in \\a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate\n * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with\n * the allocated buffer passed in \\a utilizationSamples, and \\a vgpuInstanceSamplesCount set to the number of entries the\n * buffer is sized for.\n *\n * On successful return, the function updates \\a vgpuInstanceSampleCount with the number of vGPU utilization sample\n * structures that were actually written. This may differ from a previously read value as vGPU instances are created or\n * destroyed.\n *\n * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0\n * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp\n * to a timeStamp retrieved from a previous query to read utilization since the previous query.\n *\n * @param device                        The identifier for the target device\n * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp.\n * @param sampleValType                 Pointer to caller-supplied buffer to hold the type of returned sample values\n * @param vgpuInstanceSamplesCount      Pointer to caller-supplied array size, and returns number of vGPU instances\n * @param utilizationSamples            Pointer to caller-supplied buffer in which vGPU utilization samples are returned\n\n * @return\n *         - \\ref NVML_SUCCESS                 if utilization samples are successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a vgpuInstanceSamplesCount or \\a sampleValType is\n *                                             NULL, or a sample count of 0 is passed with a non-NULL \\a utilizationSamples\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \\a vgpuInstanceSamplesCount is too small to return samples for all\n *                                             vGPU instances currently executing on the device\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if vGPU is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_NOT_FOUND         if sample entries are not found\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp,\n                                                  nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount,\n                                                  nvmlVgpuInstanceUtilizationSample_t *utilizationSamples);\n\n/**\n * Retrieves current utilization for processes running on vGPUs on a physical GPU (device).\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on\n * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the\n * caller-supplied buffer pointed at by \\a utilizationSamples. One utilization sample structure is returned per process running\n * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which\n * the samples were recorded. Individual utilization values are returned as \"unsigned int\" values.\n *\n * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with\n * \\a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance\n * count in \\a vgpuProcessSamplesCount. The caller should allocate a buffer of size\n * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with\n * the allocated buffer passed in \\a utilizationSamples, and \\a vgpuProcessSamplesCount set to the number of entries the\n * buffer is sized for.\n *\n * On successful return, the function updates \\a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample\n * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active\n * in any given sample period.\n *\n * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0\n * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp\n * to a timeStamp retrieved from a previous query to read utilization since the previous query.\n *\n * @param device                        The identifier for the target device\n * @param lastSeenTimeStamp             Return only samples with timestamp greater than lastSeenTimeStamp.\n * @param vgpuProcessSamplesCount       Pointer to caller-supplied array size, and returns number of processes running on vGPU instances\n * @param utilizationSamples            Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned\n\n * @return\n *         - \\ref NVML_SUCCESS                 if utilization samples are successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a device is invalid, \\a vgpuProcessSamplesCount or a sample count of 0 is\n *                                             passed with a non-NULL \\a utilizationSamples\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \\a vgpuProcessSamplesCount is too small to return samples for all\n *                                             vGPU instances currently executing on the device\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if vGPU is not supported by the device\n *         - \\ref NVML_ERROR_GPU_IS_LOST       if the target GPU has fallen off the bus or is otherwise inaccessible\n *         - \\ref NVML_ERROR_NOT_FOUND         if sample entries are not found\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp,\n                                                         unsigned int *vgpuProcessSamplesCount,\n                                                         nvmlVgpuProcessUtilizationSample_t *utilizationSamples);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t \n/**\n * Queries the state of per process accounting mode on vGPU.\n *\n * For Maxwell &tm; or newer fully supported devices.\n *\n * @param vgpuInstance            The identifier of the target vGPU VM\n * @param mode                    Reference in which to return the current accounting mode\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if the mode has been successfully retrieved \n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a mode is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the vGPU doesn't support this feature\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *mode);\n\n/**\n * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes \n * returned can be in running or terminated state.\n *\n * For Maxwell &tm; or newer fully supported devices.\n * \n * To just query the maximum number of processes that can be queried, call this function with *count = 0 and\n * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty.\n * \n * For more details see \\ref nvmlVgpuInstanceGetAccountingStats.\n *\n * @note In case of PID collision some processes might not be accessible before the circular buffer is full.\n *\n * @param vgpuInstance            The identifier of the target vGPU VM\n * @param count                   Reference in which to provide the \\a pids array size, and\n *                                to return the number of elements ready to be queried\n * @param pids                    Reference in which to return list of process ids\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if pids were successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a count is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the vGPU doesn't support this feature or accounting mode is disabled\n *         - \\ref NVML_ERROR_INSUFFICIENT_SIZE if \\a count is too small (\\a count is set to expected value)\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n *\n * @see nvmlVgpuInstanceGetAccountingPids\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuInstance, unsigned int *count, unsigned int *pids);\n\n/**\n * Queries process's accounting stats.\n *\n * For Maxwell &tm; or newer fully supported devices.\n * \n * Accounting stats capture GPU utilization and other statistics across the lifetime of a process, and\n * can be queried during life time of the process or after its termination.\n * The time field in \\ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and \n * updated to actual running time after its termination.\n * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old\n * processes.\n *\n * See \\ref nvmlAccountingStats_t for description of each returned metric.\n * List of processes that can be queried can be retrieved from \\ref nvmlVgpuInstanceGetAccountingPids.\n *\n * @note Accounting Mode needs to be on. See \\ref nvmlVgpuInstanceGetAccountingMode.\n * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be\n *         queried since they don't contribute to GPU utilization.\n * @note In case of pid collision stats of only the latest process (that terminated last) will be reported\n *\n * @param vgpuInstance            The identifier of the target vGPU VM\n * @param pid                     Process Id of the target process to query stats for\n * @param stats                   Reference in which to return the process's accounting stats\n *\n * @return \n *         - \\ref NVML_SUCCESS                 if stats have been successfully retrieved\n *         - \\ref NVML_ERROR_UNINITIALIZED     if the library has not been successfully initialized\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a vgpuInstance is 0, or \\a stats is NULL\n *         - \\ref NVML_ERROR_NOT_FOUND         if \\a vgpuInstance does not match a valid active vGPU instance on the system\n *                                             or \\a stats is not found\n *         - \\ref NVML_ERROR_NOT_SUPPORTED     if the vGPU doesn't support this feature or accounting mode is disabled\n *         - \\ref NVML_ERROR_UNKNOWN           on any unexpected error\n */\nnvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingStats(nvmlVgpuInstance_t vgpuInstance, unsigned int pid, nvmlAccountingStats_t *stats);\n\n/** @} */\n\n/***************************************************************************************************/\n/** @defgroup nvmlGpuBlacklistQueries GPU Blacklist Queries\n * This chapter describes NVML operations that are associated with blacklisted GPUs.\n *  @{\n */\n/***************************************************************************************************/\n\n/**\n * Blacklist GPU device information\n **/\ntypedef struct nvmlBlacklistDeviceInfo_st\n{\n    nvmlPciInfo_t pciInfo;                   //!< The PCI information for the blacklisted GPU\n    char uuid[NVML_DEVICE_UUID_BUFFER_SIZE]; //!< The ASCII string UUID for the blacklisted GPU\n} nvmlBlacklistDeviceInfo_t;\n\n /**\n * Retrieves the number of blacklisted GPU devices in the system.\n * \n * For all products.\n *\n * @param deviceCount                          Reference in which to return the number of blacklisted devices\n * \n * @return \n *         - \\ref NVML_SUCCESS                 if \\a deviceCount has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT  if \\a deviceCount is NULL\n */\nnvmlReturn_t DECLDIR nvmlGetBlacklistDeviceCount(unsigned int *deviceCount);\n\n/**\n * Acquire the device information for a blacklisted device, based on its index.\n * \n * For all products.\n *\n * Valid indices are derived from the \\a deviceCount returned by \n *   \\ref nvmlGetBlacklistDeviceCount(). For example, if \\a deviceCount is 2 the valid indices  \n *   are 0 and 1, corresponding to GPU 0 and GPU 1.\n *\n * @param index                                The index of the target GPU, >= 0 and < \\a deviceCount\n * @param info                                 Reference in which to return the device information\n * \n * @return \n *         - \\ref NVML_SUCCESS                  if \\a device has been set\n *         - \\ref NVML_ERROR_INVALID_ARGUMENT   if \\a index is invalid or \\a info is NULL\n *\n * @see nvmlGetBlacklistDeviceCount\n */\nnvmlReturn_t DECLDIR nvmlGetBlacklistDeviceInfoByIndex(unsigned int index, nvmlBlacklistDeviceInfo_t *info);\n\n/** @} */\n\n/**\n * NVML API versioning support\n */\n#if defined(__NVML_API_VERSION_INTERNAL)\n#undef nvmlDeviceGetGridLicensableFeatures\n#undef nvmlDeviceRemoveGpu\n#undef nvmlDeviceGetNvLinkRemotePciInfo\n#undef nvmlDeviceGetPciInfo\n#undef nvmlDeviceGetCount\n#undef nvmlDeviceGetHandleByIndex\n#undef nvmlDeviceGetHandleByPciBusId\n#undef nvmlInit\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vulkan/vk_util.h",
    "content": "/*\n * Copyright © 2017 Intel Corporation\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice (including the next\n * paragraph) shall be included in all copies or substantial portions of the\n * 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,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n#ifndef VK_UTIL_H\n#define VK_UTIL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* common inlines and macros for vulkan drivers */\n\n#include <vulkan/vulkan.h>\n\n#define vk_foreach_struct(__iter, __start) \\\n   for (struct VkBaseOutStructure *__iter = (struct VkBaseOutStructure *)(__start); \\\n        __iter; __iter = __iter->pNext)\n\n#define vk_foreach_struct_const(__iter, __start) \\\n   for (const struct VkBaseInStructure *__iter = (const struct VkBaseInStructure *)(__start); \\\n        __iter; __iter = __iter->pNext)\n\n/**\n * A wrapper for a Vulkan output array. A Vulkan output array is one that\n * follows the convention of the parameters to\n * vkGetPhysicalDeviceQueueFamilyProperties().\n *\n * Example Usage:\n *\n *    VkResult\n *    vkGetPhysicalDeviceQueueFamilyProperties(\n *       VkPhysicalDevice           physicalDevice,\n *       uint32_t*                  pQueueFamilyPropertyCount,\n *       VkQueueFamilyProperties*   pQueueFamilyProperties)\n *    {\n *       VK_OUTARRAY_MAKE(props, pQueueFamilyProperties,\n *                         pQueueFamilyPropertyCount);\n *\n *       vk_outarray_append(&props, p) {\n *          p->queueFlags = ...;\n *          p->queueCount = ...;\n *       }\n *\n *       vk_outarray_append(&props, p) {\n *          p->queueFlags = ...;\n *          p->queueCount = ...;\n *       }\n *\n *       return vk_outarray_status(&props);\n *    }\n */\nstruct __vk_outarray {\n   /** May be null. */\n   void *data;\n\n   /**\n    * Capacity, in number of elements. Capacity is unlimited (UINT32_MAX) if\n    * data is null.\n    */\n   uint32_t cap;\n\n   /**\n    * Count of elements successfully written to the array. Every write is\n    * considered successful if data is null.\n    */\n   uint32_t *filled_len;\n\n   /**\n    * Count of elements that would have been written to the array if its\n    * capacity were sufficient. Vulkan functions often return VK_INCOMPLETE\n    * when `*filled_len < wanted_len`.\n    */\n   uint32_t wanted_len;\n};\n\nstatic inline void\n__vk_outarray_init(struct __vk_outarray *a,\n                   void *data, uint32_t *restrict len)\n{\n   a->data = data;\n   a->cap = *len;\n   a->filled_len = len;\n   *a->filled_len = 0;\n   a->wanted_len = 0;\n\n   if (a->data == NULL)\n      a->cap = UINT32_MAX;\n}\n\nstatic inline VkResult\n__vk_outarray_status(const struct __vk_outarray *a)\n{\n   if (*a->filled_len < a->wanted_len)\n      return VK_INCOMPLETE;\n   else\n      return VK_SUCCESS;\n}\n\nstatic inline void *\n__vk_outarray_next(struct __vk_outarray *a, size_t elem_size)\n{\n   void *p = NULL;\n\n   a->wanted_len += 1;\n\n   if (*a->filled_len >= a->cap)\n      return NULL;\n\n   if (a->data != NULL)\n      p = (uint8_t *)a->data + (*a->filled_len) * elem_size;\n\n   *a->filled_len += 1;\n\n   return p;\n}\n\n#define vk_outarray(elem_t) \\\n   struct { \\\n      struct __vk_outarray base; \\\n      elem_t meta[]; \\\n   }\n\n#define vk_outarray_typeof_elem(a) __typeof__((a)->meta[0])\n#define vk_outarray_sizeof_elem(a) sizeof((a)->meta[0])\n\n#define vk_outarray_init(a, data, len) \\\n   __vk_outarray_init(&(a)->base, (data), (len))\n\n#define VK_OUTARRAY_MAKE(name, data, len) \\\n   vk_outarray(__typeof__((data)[0])) name; \\\n   vk_outarray_init(&name, (data), (len))\n\n#define vk_outarray_status(a) \\\n   __vk_outarray_status(&(a)->base)\n\n#define vk_outarray_next(a) \\\n   ((vk_outarray_typeof_elem(a) *) \\\n      __vk_outarray_next(&(a)->base, vk_outarray_sizeof_elem(a)))\n\n/**\n * Append to a Vulkan output array.\n *\n * This is a block-based macro. For example:\n *\n *    vk_outarray_append(&a, elem) {\n *       elem->foo = ...;\n *       elem->bar = ...;\n *    }\n *\n * The array `a` has type `vk_outarray(elem_t) *`. It is usually declared with\n * VK_OUTARRAY_MAKE(). The variable `elem` is block-scoped and has type\n * `elem_t *`.\n *\n * The macro unconditionally increments the array's `wanted_len`. If the array\n * is not full, then the macro also increment its `filled_len` and then\n * executes the block. When the block is executed, `elem` is non-null and\n * points to the newly appended element.\n */\n#define vk_outarray_append(a, elem) \\\n   for (vk_outarray_typeof_elem(a) *elem = vk_outarray_next(a); \\\n        elem != NULL; elem = NULL)\n\nstatic inline void *\n__vk_find_struct(void *start, VkStructureType sType)\n{\n   vk_foreach_struct(s, start) {\n      if (s->sType == sType)\n         return s;\n   }\n\n   return NULL;\n}\n\n#define vk_find_struct(__start, __sType) \\\n   __vk_find_struct((__start), VK_STRUCTURE_TYPE_##__sType)\n\n#define vk_find_struct_const(__start, __sType) \\\n   (const void *)__vk_find_struct((void *)(__start), VK_STRUCTURE_TYPE_##__sType)\n\nstatic inline void\n__vk_append_struct(void *start, void *element)\n{\n   vk_foreach_struct(s, start) {\n      if (s->pNext)\n         continue;\n\n      s->pNext = (struct VkBaseOutStructure *) element;\n      break;\n   }\n}\n\nuint32_t vk_get_driver_version(void);\n\nuint32_t vk_get_version_override(void);\n\n#define VK_EXT_OFFSET (1000000000UL)\n#define VK_ENUM_EXTENSION(__enum) \\\n   ((__enum) >= VK_EXT_OFFSET ? ((((__enum) - VK_EXT_OFFSET) / 1000UL) + 1) : 0)\n#define VK_ENUM_OFFSET(__enum) \\\n   ((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum))\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* VK_UTIL_H */\n"
  },
  {
    "path": "meson.build",
    "content": "project('MangoHud',\n  ['c', 'cpp'],\n  version : 'v0.8.3',\n  license : 'MIT',\n  meson_version: '>=0.60.0',\n  default_options : ['buildtype=release', 'c_std=c99', 'cpp_std=c++17', 'warning_level=2']\n)\n\ncc = meson.get_compiler('c')\ncpp = meson.get_compiler('cpp')\n\nprog_python = import('python').find_installation('python3', modules: ['mako'])\nnull_dep = dependency('', required : false)\n\nmangohud_version = vcs_tag(\n  command: ['git', 'describe', '--tags', '--dirty=+'],\n  input:  'version.h.in',\n  output: 'version.h')\n\nmangohud_version_dep = declare_dependency(sources : mangohud_version)\n\npre_args = [\n  '-D__STDC_CONSTANT_MACROS',\n  '-D__STDC_FORMAT_MACROS',\n  '-D__STDC_LIMIT_MACROS',\n  '-DPACKAGE_VERSION=\"@0@\"'.format(meson.project_version()),\n  '-DSPDLOG_COMPILED_LIB'\n]\n\nif get_option('buildtype') == 'debug'\n  pre_args += '-DDEBUG'\nendif\n\n# Always set max spdlog level, handle this using MANGOHUD_LOG_LEVEL instead.\npre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE'\n\n# TODO: this is very incomplete\nis_unixy = false\nif ['linux', 'cygwin', 'gnu'].contains(host_machine.system())\n  pre_args += '-D_GNU_SOURCE'\n  pre_args += '-DHAVE_PTHREAD'\n  is_unixy = true\nendif\n\nif host_machine.system() == 'linux'\n  pre_args += '-DHAVE_FTRACE'\nendif\n\nif get_option('glibcxx_asserts')\n  pre_args += '-D_GLIBCXX_ASSERTIONS'\nendif\n\n# Check for GCC style atomics\nif cc.compiles('''#include <stdint.h>\n                  int main() {\n                    struct {\n                      uint64_t *v;\n                    } x;\n                    return (int)__atomic_load_n(x.v, __ATOMIC_ACQUIRE) &\n                           (int)__atomic_add_fetch(x.v, (uint64_t)1, __ATOMIC_ACQ_REL);\n\n                  }''',\n               name : 'GCC atomic builtins')\n  pre_args += '-DUSE_GCC_ATOMIC_BUILTINS'\nendif\n\n# Not in C99, needs POSIX\nif cc.compiles('''\n                 #define _GNU_SOURCE\n                 #include <time.h>\n                  int main() {\n                    struct timespec ts;\n                    return timespec_get(&ts, TIME_UTC);\n\n                  }''',\n               name : 'Supports timespec_get')\n  pre_args += '-DHAVE_TIMESPEC_GET'\nendif\n\n# Check for GCC style builtins\nforeach b : ['bswap32', 'bswap64', 'clz', 'clzll', 'ctz', 'expect', 'ffs',\n             'ffsll', 'popcount', 'popcountll', 'unreachable']\n  if cc.has_function(b)\n    pre_args += '-DHAVE___BUILTIN_@0@'.format(b.to_upper())\n  endif\nendforeach\n\nvulkan_wsi_args = []\nvulkan_wsi_deps = []\n\nif is_unixy\n  dep_x11 = dependency('x11', required: get_option('with_x11'))\n  dep_wayland_client = dependency('wayland-client',\n      required: get_option('with_wayland'), version : '>=1.11')\n  dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true)\n  dep_xkb = dependency('xkbcommon', required: get_option('with_x11').enabled() or get_option('with_wayland').enabled())\n  vulkan_wsi_deps += dep_xkb\nelse\n  dep_x11 = null_dep\n  dep_wayland_client = null_dep\n  dbus_dep = null_dep\nendif\n\nif dep_x11.found()\n  vulkan_wsi_args += ['-DVK_USE_PLATFORM_XLIB_KHR']\n  vulkan_wsi_deps += dep_x11.partial_dependency(compile_args : true, includes : true)\nendif\nif dep_wayland_client.found()\n  vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']\n  vulkan_wsi_deps += dep_wayland_client\nendif\n\nif is_unixy and not dep_x11.found() and not dep_wayland_client.found()\n  error('At least one of \"with_x11\" and \"with_wayland\" should be enabled')\nendif\n\ninc_common = [\n    include_directories('include'),\n]\n\ndep_pthread = dependency('threads')\n\nadd_project_arguments(\n  cc.get_supported_arguments([\n    '-Werror=implicit-function-declaration',\n    '-Werror=missing-declarations',\n    '-Werror=missing-prototypes',\n    '-Werror=return-type',\n    '-Werror=incompatible-pointer-types',\n    '-Wno-unused-parameter',\n    '-Qunused-arguments',\n    '-fno-math-errno',\n    '-fno-trapping-math',\n    '-Wno-missing-field-initializers',\n  ]), language : ['c'],\n)\n\nadd_project_arguments(\n  cpp.get_supported_arguments([\n    '-Werror=missing-declarations',\n    '-Werror=return-type',\n    '-Wno-unused-parameter',\n    '-Qunused-arguments',\n    '-fno-math-errno',\n    '-fno-trapping-math',\n    '-Wno-non-virtual-dtor',\n    '-Wno-missing-field-initializers',\n  ]), language : ['cpp'],\n)\n\nforeach a : pre_args\n  add_project_arguments(a, language : ['c', 'cpp'])\nendforeach\n\n# check for dl support\nif is_unixy\n  if cc.has_function('dlopen')\n    dep_dl = null_dep\n  else\n    dep_dl = cc.find_library('dl')\n  endif\n# check for linking with rt by default\n  if cc.has_function('clock_gettime')\n    dep_rt = null_dep\n  else\n    dep_rt = cc.find_library('rt')\n  endif\nelse\n  dep_dl = null_dep\n  dep_rt = null_dep\nendif\n\n# Commented code can be used if mangohud start using latest SDK Vulkan-Headers\n# Allowing user to build mangohud using system Vulkan-Headers\n# if not dependency('VulkanHeaders').found()\n  vulkan_headers_sp = subproject('vulkan-headers')\n  vulkan_headers_api_xml = vulkan_headers_sp.get_variable('vulkan_api_xml')\n  dep_vulkan_headers = vulkan_headers_sp.get_variable('vulkan_headers_dep')\n\n  vulkan_utility_libraries_sp = subproject('vulkan-utility-libraries')\n  dep_vulkan_utility_libraries = vulkan_utility_libraries_sp.get_variable('vulkan_utility_libraries_dep')\n# else\n#  dep_vulkan_headers = dependency('VulkanHeaders', required: true)\n#  vulkan_headers_api_xml = files('/usr/share/vulkan/registry/vk.xml')\n# endif\n\nvk_enum_to_str = custom_target(\n  'vk_enum_to_str',\n  input : ['bin/gen_enum_to_str.py', vulkan_headers_api_xml],\n  output : ['vk_enum_to_str.c', 'vk_enum_to_str.h', 'vk_enum_defines.h'],\n  command : [\n    prog_python, '@INPUT0@', '--xml', '@INPUT1@',\n    '--out-c', '@OUTPUT0@',\n    '--out-h', '@OUTPUT1@',\n    '--out-d', '@OUTPUT2@',\n    '--beta', 'false'\n  ],\n)\n\nvk_dispatch_table = custom_target(\n  'vk_dispatch_table',\n  input : ['bin/vk_dispatch_table_gen.py', vulkan_headers_api_xml],\n  output : ['vk_dispatch_table.c', 'vk_dispatch_table.h'],\n  command : [\n    prog_python, '@INPUT0@', '--xml', '@INPUT1@',\n    '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@',\n    '--beta', 'false'\n  ],\n)\n\nvk_extensions = custom_target(\n  'vk_extensions',\n  input : ['bin/vk_extensions_gen.py', vulkan_headers_api_xml],\n  output : ['vk_extensions.c', 'vk_extensions.h'],\n  command : [\n    prog_python, '@INPUT0@', '--xml', '@INPUT1@',\n    '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@'\n  ],\n)\n\nimgui_options = [\n  'default_library=static',\n  'werror=false',\n  # use 'auto_features=disabled' once available: https://github.com/mesonbuild/meson/issues/5320\n  'dx9=disabled',\n  'dx10=disabled',\n  'dx11=disabled',\n  'dx12=disabled',\n  'metal=disabled',\n  'opengl=disabled',\n  'vulkan=disabled',\n  'glfw=disabled',\n  'sdl2=disabled',\n  'sdl3=disabled',\n  'osx=disabled',\n  'win=disabled',\n  'allegro5=disabled',\n  'webgpu=disabled',\n  'sdl2_renderer=disabled',\n  'sdl3_renderer=disabled',\n  'osx=disabled',\n  'win=disabled'\n]\n\nsizeof_ptr = cc.sizeof('void*')\nif sizeof_ptr == 8\n  pre_args += '-DMANGOHUD_ARCH=\"64bit\"'\nelif sizeof_ptr == 4\n  pre_args += '-DMANGOHUD_ARCH=\"32bit\"'\nendif\n\nif get_option('mangoapp')\n  imgui_options += [\n    'opengl=enabled',\n    'glfw=enabled',\n  ]\nendif\n\nimgui_sp = subproject('imgui', default_options: imgui_options)\ndearimgui_dep = imgui_sp.get_variable('imgui_dep')\n\nmeson.override_dependency('imgui', dearimgui_dep)\n\nimplot_sp = subproject('implot', default_options: ['default_library=static'])\nimplot_dep = implot_sp.get_variable('implot_dep')\n\nspdlog_options = [\n  'default_library=static',\n  'compile_library=true',\n  'werror=false',\n  'tests=disabled',\n  'external_fmt=disabled',\n  'std_format=disabled'\n]\n\nspdlog_dep = dependency('spdlog', required: false)\n\nif get_option('use_system_spdlog').disabled() or not spdlog_dep.found()\n    if get_option('use_system_spdlog').enabled()\n      warning('spdlog dependency not found following back to submodule')\n    endif\n    spdlog_sp = subproject('spdlog', default_options: spdlog_options)\n    spdlog_dep = spdlog_sp.get_variable('spdlog_dep')\nendif\n\nif ['windows', 'mingw'].contains(host_machine.system())\n  minhook_dep = dependency('minhook', fallback: ['minhook', 'minhook_dep'], required: true)\n  windows_deps = [\n    minhook_dep,\n  ]\nelse\n  windows_deps = null_dep\nendif\n\nif get_option('mangoapp')\n  glfw3_dep = dependency('glfw3')\nendif\n\nsubdir('src')\n\nif get_option('include_doc')\n  subdir('data')\nendif\n\nif get_option('tests').enabled()\n  # cmocka_dep = dependency('cmocka', fallback: ['cmocka', 'cmocka_dep'])\n\n  # e = executable('amdgpu', 'tests/test_amdgpu.cpp',\n  #   files(\n  #     'src/amdgpu.cpp',\n  #     'src/cpu.cpp',\n  #     'src/gpu.cpp',\n  #     'src/gpu_fdinfo.cpp',\n  #     'src/nvidia.cpp',\n  #     'src/mesa/util/os_time.c',\n  #     'src/file_utils.cpp',\n  #     'src/hud_elements.cpp'\n  #   ),\n  #   cpp_args: ['-DTEST_ONLY'],\n  #   dependencies: [\n  #     cmocka_dep,\n  #     spdlog_dep,\n  #     implot_dep,\n  #     dearimgui_dep\n  #   ],\n  #   include_directories: inc_common)\n\n  # test('test amdgpu', e, workdir : meson.project_source_root() + '/tests')\n\nendif\n\n# install helper scripts\nif get_option('mangoplot').enabled()\n  subdir('bin')\nendif\n"
  },
  {
    "path": "meson_options.txt",
    "content": "option('glibcxx_asserts', type : 'boolean', value : false)\noption('use_system_spdlog', type : 'feature', value : 'disabled', description: 'Use system spdlog library')\noption('append_libdir_mangohud', type : 'boolean', value : true, description: 'Append \"mangohud\" to libdir path or not.')\noption('include_doc', type : 'boolean', value : true, description: 'Include the example config, man pages, appstream files etc.')\noption('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support')\noption('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support')\noption('with_x11', type : 'feature', value : 'enabled')\noption('with_wayland', type : 'feature', value : 'enabled')\noption('with_dbus', type : 'feature', value : 'enabled')\noption('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')\noption('mangoapp', type: 'boolean', value : false)\noption('mangohudctl', type: 'boolean', value : false)\noption('tests', type: 'feature', value: 'auto', description: 'Run tests')\noption('mangoplot', type: 'feature', value: 'enabled')\noption('dynamic_string_tokens', type: 'boolean', value: true, description: 'Use dynamic string tokens in LD_PRELOAD')\noption('with_fex', type : 'boolean', value : false)\n"
  },
  {
    "path": "mingw32.txt",
    "content": "[binaries]\nc = 'i686-w64-mingw32-gcc'\ncpp = 'i686-w64-mingw32-g++'\nar = 'i686-w64-mingw32-ar'\nstrip = 'i686-w64-mingw32-strip'\npkg-config = 'i686-w64-mingw32-pkg-config'\nsh = '/usr/bin/sh'\n\n[properties]\nneeds_exe_wrapper = true\n\n[host_machine]\nsystem = 'windows'\ncpu_family = 'x86'\ncpu = 'i686'\nendian = 'little'\n"
  },
  {
    "path": "mingw64.txt",
    "content": "[binaries]\nc = 'x86_64-w64-mingw32-gcc'\ncpp = 'x86_64-w64-mingw32-g++'\nar = 'x86_64-w64-mingw32-ar'\nstrip = 'x86_64-w64-mingw32-strip'\npkg-config = 'x86_64-w64-mingw32-pkg-config'\nsh = '/usr/bin/sh'\n\n[properties]\nneeds_exe_wrapper = true\n\n[host_machine]\nsystem = 'windows'\ncpu_family = 'x86_64'\ncpu = 'x86_64'\nendian = 'little'\n"
  },
  {
    "path": "pkgbuild/PKGBUILD",
    "content": "# Maintainer: Simon Hallsten <flightlessmangoyt@gmail.com>\n\npkgname=('mangohud' 'lib32-mangohud')\npkgver=0.8.3.rc1.r36.ga2a54f5e\npkgrel=1\npkgdesc=\"Vulkan and OpenGL overlay to display performance information\"\narch=('x86_64')\nmakedepends=('dbus' 'gcc' 'meson' 'python-mako' 'libx11' 'lib32-libx11' 'git' 'pkgconf' 'vulkan-headers')\ndepends=('glslang' 'libglvnd' 'lib32-libglvnd' 'glfw' 'python-numpy' 'python-matplotlib'\n         'libxrandr' 'libxkbcommon' 'lib32-libxkbcommon')\nreplaces=('vulkan-mesa-layer-mango')\nlicense=('MIT')\nsource=(\n        \"mangohud\"::\"git+https://github.com/flightlessmango/MangoHud.git#branch=master\"\n        \"mangohud-minhook\"::\"git+https://github.com/flightlessmango/minhook.git\"\n        \"imgui-1.91.6.tar.gz::https://github.com/ocornut/imgui/archive/refs/tags/v1.91.6.tar.gz\"\n        \"imgui_1.91.6-3_patch.zip::https://wrapdb.mesonbuild.com/v2/imgui_1.91.6-3/get_patch\"\n        \"spdlog-1.14.1.tar.gz::https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz\"\n        \"spdlog_1.14.1-1_patch.zip::https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch\"\n        \"vulkan-headers-1.4.346.tar.gz::https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.346.tar.gz\"\n        \"vulkan-utility-libraries-1.4.346.tar.gz::https://github.com/KhronosGroup/Vulkan-Utility-Libraries/archive/v1.4.346.tar.gz\"\n        \"implot-0.16.zip::https://github.com/epezent/implot/archive/refs/tags/v0.16.zip\"\n        \"implot_0.16-1_patch.zip::https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch\"\n        )\n\nsha256sums=(\n            'SKIP'\n            'SKIP'\n            'c5fbc5dcab1d46064001c3b84d7a88812985cde7e0e9ced03f5677bec1ba502a'\n            '2f7977114ba07d06559aaf8890a92a4ebd25186592d4447954605aaf2244634d'\n            '1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b'\n            'ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c'\n            \"5bb77f5d7b460e255a9e51affc00d64354986b55cf577d8eab28529cad01fc80\"\n            \"372eb525103ecb4e3a04d030b2a9778ebc67853bbdc82ce6747de3757d432ad9\"\n            \"24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708\"\n            \"1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7\"\n            )\n\n_build_args=\"-Dappend_libdir_mangohud=false -Dwith_xnvctrl=disabled -Dtests=disabled\"\n\npkgver() {\n  cd \"$srcdir/mangohud\"\n  git describe --tags | sed -r 's/^v//;s/([^-]*-g)/r\\1/;s/-/./g'\n}\n\nprepare() {\n  cd \"${srcdir}/mangohud\"\n  git submodule init\n  git config submodule.modules/minhook.url \"$srcdir/mangohud-minhook\"\n  git -c protocol.file.allow=always submodule update\n\n  # meson subprojects\n  ln -sv \"$srcdir/imgui-1.91.6\" subprojects\n  ln -sv \"$srcdir/spdlog-1.14.1\" subprojects\n  ln -sv \"$srcdir/Vulkan-Headers-1.4.346\" subprojects\n  cp -rvt \"subprojects/Vulkan-Headers-1.4.346\" -- \"subprojects/packagefiles/vulkan-headers/\"*\n  ln -sv \"$srcdir/Vulkan-Utility-Libraries-1.4.346\" subprojects\n  cp -rvt \"subprojects/Vulkan-Utility-Libraries-1.4.346\" -- \"subprojects/packagefiles/vulkan-utility-libraries/\"*\n  ln -sv \"$srcdir/implot-0.16\" subprojects\n}\n\nbuild() {\n  arch-meson mangohud build64 \\\n    ${_build_args} -Dmangoapp=true -Dmangohudctl=true\n\n  ninja -C build64\n  export CC=\"${CC:-gcc} -m32\"\n  export CXX=\"${CXX:-g++} -m32\"\n  export PKG_CONFIG_PATH=\"/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}\"\n  export LLVM_CONFIG=\"/usr/bin/llvm-config32\"\n\n  arch-meson mangohud build32 \\\n    --libdir=lib32 \\\n    -Dmangoapp=false \\\n    -Dmangohudctl=false \\\n    ${_build_args}\n\n  ninja -C build32\n}\n\npackage_mangohud() {\n  provides=(\"mangohud\")\n  conflicts=('mangohud-common')\n  DESTDIR=\"${pkgdir}\" ninja -C build64 install\n}\n\npackage_lib32-mangohud() {\n  provides=(\"lib32-mangohud\")\n  DESTDIR=\"${pkgdir}\" ninja -C build32 install\n  rm -rf \"$pkgdir/usr/bin\"\n  rm -rf \"$pkgdir/usr/share\"\n  install -m644 -Dt \"$pkgdir/usr/share/vulkan/implicit_layer.d\" \"$srcdir/build32/src/MangoHud.x86.json\"\n}\n"
  },
  {
    "path": "src/amdgpu.cpp",
    "content": "#include <spdlog/spdlog.h>\n#include <thread>\n#ifdef __linux__\n#include <sys/sysinfo.h>\n#endif\n#include \"amdgpu.h\"\n#include \"gpu.h\"\n#include \"cpu.h\"\n#include \"overlay.h\"\n#include \"hud_elements.h\"\n#include \"logging.h\"\n#include \"mesa/util/macros.h\"\n\n\n#define IS_VALID_METRIC(FIELD) (FIELD != 0xffff)\nvoid AMDGPU::get_instant_metrics(struct amdgpu_common_metrics *metrics) {\n\tFILE *f;\n\tuint8_t buf[sizeof(struct gpu_metrics_v3_0)+1];  // big enough for v1.3/v2.4/v3.0\n\tstruct metrics_table_header *header = (struct metrics_table_header *)buf;\n\n\tf = fopen(gpu_metrics_path.c_str(), \"rb\");\n\tif (!f)\n\t\treturn;\n\n\tsize_t nread = fread(buf, 1, sizeof(buf), f);\n\tfclose(f);\n\n\tif (nread < sizeof(*header)) {\n\t\tSPDLOG_DEBUG(\"amdgpu metrics file '{}' may be corrupted (read {} bytes, need at least {})\",\n\t\t\t\t\tgpu_metrics_path, nread, sizeof(*header));\n\t\treturn;\n\t}\n\n\tif (nread == sizeof(buf)) {\n\t\t// File may be larger than our buffer, so we might have truncated it\n\t\tSPDLOG_DEBUG(\"amdgpu metrics file '{}' may be larger than the buffer ({} bytes)\",\n\t\t\t\t\tgpu_metrics_path, sizeof(buf));\n\t\treturn;\n\t}\n\n\tbool is_power=false, is_current=false, is_temp=false, is_other=false;\n\tif (header->format_revision == 1) {\n\t\t// Desktop GPUs\n\t\tstruct gpu_metrics_v1_3 *amdgpu_metrics = (struct gpu_metrics_v1_3 *) buf;\n\t\tmetrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;\n\n\t\tmetrics->average_gfx_power_w = amdgpu_metrics->average_socket_power;\n\n\t\tmetrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk;\n\t\tmetrics->current_uclk_mhz = amdgpu_metrics->current_uclk;\n\n\t\tmetrics->gpu_temp_c = amdgpu_metrics->temperature_edge;\n\t\tmetrics->fan_speed = amdgpu_metrics->current_fan_speed;\n\n\t\tuint64_t indep = amdgpu_metrics->indep_throttle_status;\n\t\t// RDNA 3 almost always shows the TEMP_HOTSPOT throtting flag,\n\t\t// so clear that bit\n\t\tindep &= ~(1ull << TEMP_HOTSPOT_BIT);  // your existing quirk\n\n\t\tis_power   = ((indep >> 0)  & 0xFF) != 0;\n\t\tis_current = ((indep >> 16) & 0xFF) != 0;\n\t\tis_temp    = ((indep >> 32) & 0xFFFF) != 0;\n\t\tis_other   = ((indep >> 56) & 0xFF) != 0;\n\t\tif (throttling)\n\t\t\tthrottling->indep_throttle_status = indep;\n\t} else if (header->format_revision == 2) {\n\t\t// APUs\n\t\tthis->is_apu = true;\n\t\tstruct gpu_metrics_v2_3 *amdgpu_metrics = (struct gpu_metrics_v2_3 *) buf;\n\n\t\tmetrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;\n\n\t\tmetrics->average_gfx_power_w = amdgpu_metrics->average_gfx_power / 1000.f;\n\n\t\tif( IS_VALID_METRIC(amdgpu_metrics->average_cpu_power) ) {\n\t\t\t// prefered method\n\t\t\tmetrics->average_cpu_power_w = amdgpu_metrics->average_cpu_power / 1000.f;\n\t\t} else if( IS_VALID_METRIC(amdgpu_metrics->average_core_power[0]) ) {\n\t\t\t// fallback 1: sum of core power\n\t\t\tmetrics->average_cpu_power_w = 0;\n\t\t\tunsigned i = 0;\n\t\t\tdo metrics->average_cpu_power_w = metrics->average_cpu_power_w + amdgpu_metrics->average_core_power[i] / 1000.f;\n\t\t\twhile (++i < ARRAY_SIZE(amdgpu_metrics->average_core_power) && IS_VALID_METRIC(amdgpu_metrics->average_core_power[i]));\n\t\t} else if( IS_VALID_METRIC(amdgpu_metrics->average_socket_power) && IS_VALID_METRIC(amdgpu_metrics->average_gfx_power) ) {\n\t\t\t// fallback 2: estimate cpu power frostd::string pci_dev, uint32_t deviceID, uint32_t vendorID\n\t\t\tmetrics->soc_temp_c = 0;\n\t\t}\n\t\tif( IS_VALID_METRIC(amdgpu_metrics->temperature_gfx) ) {\n\t\t\t// prefered method\n\t\t\tmetrics->gpu_temp_c = amdgpu_metrics->temperature_gfx / 100;\n\t\t} else if( header->content_revision >= 3 && IS_VALID_METRIC(amdgpu_metrics->average_temperature_gfx) ) {\n\t\t\t// fallback 1\n\t\t\tmetrics->gpu_temp_c = amdgpu_metrics->average_temperature_gfx / 100;\n\t\t} else {\n\t\t\t// giving up\n\t\t\tmetrics->gpu_temp_c = 0;\n\t\t}\n\n\t\tint cpu_temp = 0;\n\t\tif( IS_VALID_METRIC(amdgpu_metrics->temperature_core[0]) ) {\n\t\t\t// prefered method\n\t\t\tunsigned i = 0;\n\t\t\tdo cpu_temp = MAX(cpu_temp, amdgpu_metrics->temperature_core[i]);\n\t\t\twhile (++i < ARRAY_SIZE(amdgpu_metrics->temperature_core) && IS_VALID_METRIC(amdgpu_metrics->temperature_core[i]));\n\t\t\tmetrics->apu_cpu_temp_c = cpu_temp / 100;\n\t\t} else if( header->content_revision >= 3 && IS_VALID_METRIC(amdgpu_metrics->average_temperature_core[0]) ) {\n\t\t\t// fallback 1\n\t\t\tunsigned i = 0;\n\t\t\tdo cpu_temp = MAX(cpu_temp, amdgpu_metrics->average_temperature_core[i]);\n\t\t\twhile (++i < ARRAY_SIZE(amdgpu_metrics->average_temperature_core) && IS_VALID_METRIC(amdgpu_metrics->average_temperature_core[i]));\n\t\t\tmetrics->apu_cpu_temp_c = cpu_temp / 100;\n\t\t} else if( cpuStats.ReadcpuTempFile(cpu_temp) ) {\n\t\t\t// fallback 2: Try temp from file 'm_cpuTempFile' of 'cpu.cpp'\n\t\t\tmetrics->apu_cpu_temp_c = cpu_temp;\n\t\t} else {\n\t\t\t// giving up\n\t\t\tmetrics->apu_cpu_temp_c = 0;\n\t\t}\n\n\t\tif( IS_VALID_METRIC(amdgpu_metrics->current_gfxclk) ) {\n\t\t\t// prefered method\n\t\t\tmetrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk;\n\t\t} else if( IS_VALID_METRIC(amdgpu_metrics->average_gfxclk_frequency) ) {\n\t\t\t// fallback 1\n\t\t\tmetrics->current_gfxclk_mhz = amdgpu_metrics->average_gfxclk_frequency;\n\t\t} else {\n\t\t\t// giving up\n\t\t\tmetrics->current_gfxclk_mhz = 0;\n\t\t}\n\n\t\tif( IS_VALID_METRIC(amdgpu_metrics->current_uclk) ) {\n\t\t\t// prefered method\n\t\t\tmetrics->current_uclk_mhz = amdgpu_metrics->current_uclk;\n\t\t} else if( IS_VALID_METRIC(amdgpu_metrics->average_uclk_frequency) ) {\n\t\t\t// fallback 1\n\t\t\tmetrics->current_uclk_mhz = amdgpu_metrics->average_uclk_frequency;\n\t\t} else {\n\t\t\t// giving up\n\t\t\tmetrics->current_uclk_mhz = 0;\n\t\t}\n\n\t\tif(header->content_revision >= 2) {\n\t\t\tuint64_t indep = amdgpu_metrics->indep_throttle_status;\n\t\t\tis_power   = ((indep >> 0)  & 0xFF) != 0;\n\t\t\tis_current = ((indep >> 16) & 0xFF) != 0;\n\t\t\tis_temp    = ((indep >> 32) & 0xFFFF) != 0;\n\t\t\tis_other   = ((indep >> 56) & 0xFF) != 0;\n\t\tif (throttling)\n\t\t\t\tthrottling->indep_throttle_status = indep;\n\t\t}\n\t} else if (header->format_revision == 3) {\n\t\tthis->is_apu = true;\n\t\tstruct gpu_metrics_v3_0 *amdgpu_metrics = (struct gpu_metrics_v3_0 *) buf;\n\n\t\tmetrics->gpu_temp_c = amdgpu_metrics->temperature_gfx / 100;\n\t\tmetrics->soc_temp_c = amdgpu_metrics->temperature_soc / 100;\n\n\t\tuint16_t cpu_temp = 0;\n\n\t\tfor (unsigned i = 0; i < ARRAY_SIZE(amdgpu_metrics->temperature_core); i++) {\n\t\t\tif (!IS_VALID_METRIC(amdgpu_metrics->temperature_core[i]))\n\t\t\t\tbreak;\n\n\t\t\tcpu_temp = MAX(cpu_temp, amdgpu_metrics->temperature_core[i]);\n\t\t}\n\t\tmetrics->apu_cpu_temp_c = cpu_temp / 100;\n\n\t\tmetrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity;\n\t\t// average_apu_power includes gfx_power so remove that from cpu_power\n\t\tint64_t apu_power = amdgpu_metrics->average_apu_power;\n\t\tint64_t gfx_power = amdgpu_metrics->average_gfx_power;\n\t\tmetrics->average_cpu_power_w = float(apu_power - gfx_power) / 1000.0;\n\t\tif (metrics->average_cpu_power_w < 0) metrics->average_cpu_power_w = 0;\n\t\tmetrics->average_gfx_power_w = amdgpu_metrics->average_gfx_power / 1000.0;\n\t\tmetrics->current_gfxclk_mhz = amdgpu_metrics->average_gfxclk_frequency;\n\t\tmetrics->current_uclk_mhz = amdgpu_metrics->average_uclk_frequency;\n\t\t\n\t\tif (previous_metrics.common_header.structure_size == 0) {\n\t\t\tprevious_metrics = *amdgpu_metrics;\n\t\t\tis_temp = false;\n\t\t\tis_power = false;\n\t\t\tis_current = false;\n\t\t\tis_other = false;\n\t\t\tif (throttling) {\n\t\t\t\tthrottling->use_v3 = true;\n\t\t\t\tthrottling->v3_power.store(false);\n\t\t\t\tthrottling->v3_thermal.store(false);\n\t\t\t}\n\t\t\treturn;\t\n\t\t} else {\n\t\t\tuint32_t d_thm_core = V3_THROTTLING_DELTA(thm_core);\n\t\t\tuint32_t d_thm_gfx  = V3_THROTTLING_DELTA(thm_gfx);\n\t\t\tuint32_t d_thm_soc  = V3_THROTTLING_DELTA(thm_soc);\n\t\t\tuint32_t d_spl      = V3_THROTTLING_DELTA(spl);\n\t\t\tuint32_t d_fppt     = V3_THROTTLING_DELTA(fppt);\n\t\t\tuint32_t d_sppt     = V3_THROTTLING_DELTA(sppt);\n\t\t\tuint32_t d_prochot  = V3_THROTTLING_DELTA(prochot);\n\t\t\tis_temp = (d_thm_core | d_thm_gfx | d_thm_soc | d_prochot) > 0;\n\t\t\tis_power = (d_spl | d_fppt | d_sppt) > 0;\n\t\t\t// there is no current throttling flags in v3_0\n\t\t\tis_current = false;\n\t\t\t// also no \"other\" throttling in v3_0\n\t\t\tis_other = false;\n\n\t\t\tprevious_metrics = *amdgpu_metrics;\n\n\t\t\tif (throttling) {\n\t\t\t\tthrottling->use_v3 = true;\n\t\t\t\t// we only check spl, this attempts to match how we handle it in v1 and v2\n\t\t\t\t// as close as we can\n\t\t\t\tthrottling->v3_power.store(d_spl > 0);\n\t\t\t\tthrottling->v3_thermal.store(is_temp);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Throttling: See\n\thttps://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h\n\tfor the offsets */\n\tmetrics->is_power_throttled   = is_power;\n\tmetrics->is_current_throttled = is_current;\n\tmetrics->is_temp_throttled    = is_temp;\n\tmetrics->is_other_throttled   = is_other;\n}\n\nvoid AMDGPU::get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT], bool &gpu_load_needs_dividing) {\n\twhile (!stop_thread) {\n\t\t// Get all the samples\n\t\tfor (size_t cur_sample_id=0; cur_sample_id < METRICS_SAMPLE_COUNT; cur_sample_id++) {\n\t\t\tif (gpu_metrics_is_valid)\n\t\t\t\tget_instant_metrics(&metrics_buffer[cur_sample_id]);\n\n\t\t\t// Detect and fix if the gpu load is reported in centipercent\n\t\t\tif (gpu_load_needs_dividing || metrics_buffer[cur_sample_id].gpu_load_percent > 100){\n\t\t\t\tgpu_load_needs_dividing = true;\n\t\t\t\tmetrics_buffer[cur_sample_id].gpu_load_percent /= 100;\n\t\t\t}\n\n\t\t\t// frequently check if thread should stop so we don't get stuck for 500ms\n\t\t\tfor (int ms = 0; ms < METRICS_POLLING_PERIOD_MS; ms++) {\n\t\t\t\tif (stop_thread) break;\n\t\t\t\tusleep(1000);\n\t\t\t}\n\t\t}\n\n\t\tif (stop_thread) break;\n\n        std::unique_lock<std::mutex> lock(metrics_mutex);\n        cond_var.wait(lock, [this]() { return !paused || stop_thread; });\n\t\t// do one pass of metrics from sysfs nodes\n\t\t// then we replace with GPU metrics if it's available\n\t\tget_sysfs_metrics();\n\n#ifndef TEST_ONLY\n\t\tmetrics.proc_vram_used = fdinfo_helper->amdgpu_helper_get_proc_vram();\n#endif\n\n\t\tif (gpu_metrics_is_valid) {\n\t\t\tUPDATE_METRIC_AVERAGE(gpu_load_percent);\n\t\t\tUPDATE_METRIC_AVERAGE_FLOAT(average_gfx_power_w);\n\t\t\tUPDATE_METRIC_AVERAGE_FLOAT(average_cpu_power_w);\n\n\t\t\tUPDATE_METRIC_AVERAGE(current_gfxclk_mhz);\n\t\t\tUPDATE_METRIC_AVERAGE(current_uclk_mhz);\n\n\t\t\tUPDATE_METRIC_AVERAGE(soc_temp_c);\n\t\t\tUPDATE_METRIC_AVERAGE(gpu_temp_c);\n\t\t\tUPDATE_METRIC_AVERAGE(apu_cpu_temp_c);\n\n\t\t\tUPDATE_METRIC_MAX(is_power_throttled);\n\t\t\tUPDATE_METRIC_MAX(is_current_throttled);\n\t\t\tUPDATE_METRIC_MAX(is_temp_throttled);\n\t\t\tUPDATE_METRIC_MAX(is_other_throttled);\n\n\t\t\tUPDATE_METRIC_MAX(fan_speed);\n\t\t\tmetrics.fan_rpm = true;\n\n\t\t\tmetrics.load = amdgpu_common_metrics.gpu_load_percent;\n\t\t\tmetrics.powerUsage = amdgpu_common_metrics.average_gfx_power_w;\n\t\t\tmetrics.MemClock = amdgpu_common_metrics.current_uclk_mhz;\n\n\t\t\t// Use hwmon instead, see gpu.cpp\n\t\t\tif ( device_id == 0x1435 || device_id == 0x163f )\n\t\t\t{\n\t\t\t\t// If we are on VANGOGH (Steam Deck), then\n\t\t\t\t// always use core clock from GPU metrics.\n\t\t\t\tmetrics.CoreClock = amdgpu_common_metrics.current_gfxclk_mhz;\n\t\t\t}\n\t\t\tmetrics.temp = amdgpu_common_metrics.gpu_temp_c;\n\t\t\tmetrics.apu_cpu_power = amdgpu_common_metrics.average_cpu_power_w;\n\t\t\tmetrics.apu_cpu_temp = amdgpu_common_metrics.apu_cpu_temp_c;\n\n\t\t\tmetrics.is_power_throttled = amdgpu_common_metrics.is_power_throttled;\n\t\t\tmetrics.is_current_throttled = amdgpu_common_metrics.is_current_throttled;\n\t\t\tmetrics.is_temp_throttled = amdgpu_common_metrics.is_temp_throttled;\n\t\t\tmetrics.is_other_throttled = amdgpu_common_metrics.is_other_throttled;\n\n\t\t\t// Set only if gpu_metrics has value larger than 0, otherwise use hwmon\n\t\t\tif (amdgpu_common_metrics.fan_speed > 0)\n\t\t\t\tmetrics.fan_speed = amdgpu_common_metrics.fan_speed;\n\t\t}\n\t}\n}\n\nvoid AMDGPU::metrics_polling_thread() {\n\tstruct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT];\n\tbool gpu_load_needs_dividing = false;  //some GPUs report load as centipercent\n\n\t// Initial poll of the metrics, so that we have values to display as fast as possible\n\tget_instant_metrics(&amdgpu_common_metrics);\n\tif (amdgpu_common_metrics.gpu_load_percent > 100){\n\t\tgpu_load_needs_dividing = true;\n\t\tamdgpu_common_metrics.gpu_load_percent /= 100;\n\t}\n\n\t// Set all the fields to 0 by default. Only done once as we're just replacing previous values after\n\tmemset(metrics_buffer, 0, sizeof(metrics_buffer));\n\n\twhile (!stop_thread) {\n#ifndef TEST_ONLY\n\t\tif (get_params()->no_display && !logger->is_active())\n\t\t\tusleep(100000);\n\t\telse\n#endif\n\t\t\tget_samples_and_copy(metrics_buffer, gpu_load_needs_dividing);\n\t}\n}\n\nvoid AMDGPU::get_sysfs_metrics() {\n    int64_t value = 0;\n\tif (sysfs_nodes.busy) {\n\t\trewind(sysfs_nodes.busy);\n\t\tfflush(sysfs_nodes.busy);\n\t\tint value = 0;\n\t\tif (fscanf(sysfs_nodes.busy, \"%d\", &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.load = value;\n\t}\n\n\tif (sysfs_nodes.memory_clock) {\n\t\trewind(sysfs_nodes.memory_clock);\n\t\tfflush(sysfs_nodes.memory_clock);\n\t\tif (fscanf(sysfs_nodes.memory_clock, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\n\t\tmetrics.MemClock = value / 1000000;\n\t}\n\n\t// TODO: on some gpus this will use the power1_input instead\n\t// this value is instantaneous and should be averaged over time\n\t// probably just average everything in this function to be safe\n#ifndef TEST_ONLY\n\tif (get_params()->enabled[OVERLAY_PARAM_ENABLED_gpu_power]) {\n\t\t// NOTE: Do not read power1_average if it is not enabled, as some\n\t\t// older GPUs may hang when reading the sysfs node.\n\t\tmetrics.powerUsage = 0;\n\t} else\n#endif\n\tif (sysfs_nodes.power_usage) {\n\t\trewind(sysfs_nodes.power_usage);\n\t\tfflush(sysfs_nodes.power_usage);\n\t\tif (fscanf(sysfs_nodes.power_usage, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\n\t\tmetrics.powerUsage = value / 1000000;\n\t}\n\n#ifndef TEST_ONLY\n\tif (!get_params()->enabled[OVERLAY_PARAM_ENABLED_gpu_power_limit]) {\n\t\t// NOTE: Do not read power1_cap if it is not enabled, as some\n\t\t// older GPUs may hang when reading the sysfs node.\n\t\tmetrics.powerLimit = 0;\n\t} else\n#endif\n\tif (sysfs_nodes.power_limit) {\n\t\trewind(sysfs_nodes.power_limit);\n\t\tfflush(sysfs_nodes.power_limit);\n\t\tif (fscanf(sysfs_nodes.power_limit, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\n\t\tmetrics.powerLimit = value / 1000000;\n\t}\n\n\tif (sysfs_nodes.fan) {\n\t\trewind(sysfs_nodes.fan);\n\t\tfflush(sysfs_nodes.fan);\n\t\tif (fscanf(sysfs_nodes.fan, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.fan_speed = value;\n\t\tmetrics.fan_rpm = true;\n\t}\n\n\tif (sysfs_nodes.vram_total) {\n\t\trewind(sysfs_nodes.vram_total);\n\t\tfflush(sysfs_nodes.vram_total);\n\t\tif (fscanf(sysfs_nodes.vram_total, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.memoryTotal = float(value) / (1024 * 1024 * 1024);\n\t}\n\n\tif (sysfs_nodes.vram_used) {\n\t\trewind(sysfs_nodes.vram_used);\n\t\tfflush(sysfs_nodes.vram_used);\n\t\tif (fscanf(sysfs_nodes.vram_used, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.sys_vram_used = float(value) / (1024 * 1024 * 1024);\n\t}\n\t// On some GPUs SMU can sometimes return the wrong temperature.\n\t// As HWMON is way more visible than the SMU metrics, let's always trust it as it is the most likely to work\n\tif (sysfs_nodes.core_clock) {\n\t\trewind(sysfs_nodes.core_clock);\n\t\tfflush(sysfs_nodes.core_clock);\n\t\tif (fscanf(sysfs_nodes.core_clock, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\n\t\tmetrics.CoreClock = value / 1000000;\n\t}\n\n\tif (sysfs_nodes.temp){\n\t\trewind(sysfs_nodes.temp);\n\t\tfflush(sysfs_nodes.temp);\n\t\tint value = 0;\n\t\tif (fscanf(sysfs_nodes.temp, \"%d\", &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.temp = value / 1000;\n\t}\n\n\tif (sysfs_nodes.junction_temp){\n\t\trewind(sysfs_nodes.junction_temp);\n\t\tfflush(sysfs_nodes.junction_temp);\n\t\tint value = 0;\n\t\tif (fscanf(sysfs_nodes.junction_temp, \"%d\", &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.junction_temp = value / 1000;\n\t}\n\n\tif (sysfs_nodes.memory_temp){\n\t\trewind(sysfs_nodes.memory_temp);\n\t\tfflush(sysfs_nodes.memory_temp);\n\t\tint value = 0;\n\t\tif (fscanf(sysfs_nodes.memory_temp, \"%d\", &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.memory_temp = value / 1000;\n\t}\n\n\tif (sysfs_nodes.gtt_used) {\n\t\trewind(sysfs_nodes.gtt_used);\n\t\tfflush(sysfs_nodes.gtt_used);\n\t\tif (fscanf(sysfs_nodes.gtt_used, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.gtt_used = float(value) / (1024 * 1024 * 1024);\n\t}\n\n\tif (sysfs_nodes.gpu_voltage_soc) {\n\t\trewind(sysfs_nodes.gpu_voltage_soc);\n\t\tfflush(sysfs_nodes.gpu_voltage_soc);\n\t\tif (fscanf(sysfs_nodes.gpu_voltage_soc, \"%\" PRId64, &value) != 1)\n\t\t\tvalue = 0;\n\t\tmetrics.voltage = value;\n\t}\n}\n\nAMDGPU::AMDGPU(std::string pci_dev, uint32_t device_id, uint32_t vendor_id) {\n\tthis->pci_dev = pci_dev;\n\tthis->device_id = device_id;\n\tthis->vendor_id = vendor_id;\n\tconst std::string device_path = \"/sys/bus/pci/devices/\" + pci_dev;\n\tgpu_metrics_path = device_path + \"/gpu_metrics\";\n    // Just check that the metrics file exists and is readable\n    FILE *f = fopen(gpu_metrics_path.c_str(), \"rb\");\n    if (f) {\n        gpu_metrics_is_valid = true;\n        fclose(f);\n    } else {\n        gpu_metrics_is_valid = false;\n        SPDLOG_DEBUG(\"Failed to open gpu_metrics at '{}'\", gpu_metrics_path);\n    }\n\n\tsysfs_nodes.busy = fopen((device_path + \"/gpu_busy_percent\").c_str(), \"r\");\n\tsysfs_nodes.vram_total = fopen((device_path + \"/mem_info_vram_total\").c_str(), \"r\");\n\tsysfs_nodes.vram_used = fopen((device_path + \"/mem_info_vram_used\").c_str(), \"r\");\n\tsysfs_nodes.gtt_used = fopen((device_path + \"/mem_info_gtt_used\").c_str(), \"r\");\n\n\tconst std::string hwmon_path = device_path + \"/hwmon/\";\n\tif (fs::exists(hwmon_path)){\n\t\tconst auto dirs = ls(hwmon_path.c_str(), \"hwmon\", LS_DIRS);\n\t\tfor (const auto& dir : dirs) {\n\t\t\tsysfs_nodes.temp = fopen((hwmon_path + dir + \"/temp1_input\").c_str(), \"r\");\n\t\t\tsysfs_nodes.junction_temp = fopen((hwmon_path + dir + \"/temp2_input\").c_str(), \"r\");\n\t\t\tsysfs_nodes.memory_temp = fopen((hwmon_path + dir + \"/temp3_input\").c_str(), \"r\");\n\t\t\tsysfs_nodes.core_clock = fopen((hwmon_path + dir + \"/freq1_input\").c_str(), \"r\");\n\t\t\tsysfs_nodes.gpu_voltage_soc = fopen((hwmon_path + dir + \"/in0_input\").c_str(), \"r\");\n\t\t\tsysfs_nodes.memory_clock = fopen((hwmon_path + dir + \"/freq2_input\").c_str(), \"r\");\n\n\t\t\tfor (std::string p : { \"power1_average\", \"power1_input\" }) {\n\t\t\t\tstd::string sensor = hwmon_path + dir + \"/\" + p;\n\n\t\t\t\tif (!fs::exists(sensor))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tsysfs_nodes.power_usage = fopen(sensor.c_str(), \"r\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tsysfs_nodes.power_limit = fopen((hwmon_path + dir + \"/power1_cap\").c_str(), \"r\");\n\t\t\tsysfs_nodes.fan = fopen((hwmon_path + dir + \"/fan1_input\").c_str(), \"r\");\n\t\t}\n\t}\n\n\tthrottling = std::make_shared<Throttling>(0x1002);\n#ifndef TEST_ONLY\n\tfdinfo_helper = std::make_unique<GPU_fdinfo>(\"amdgpu\", pci_dev, \"\", /*called_from_amdgpu_cpp=*/ true);\n#endif\n\n\tthread = std::thread(&AMDGPU::metrics_polling_thread, this);\n\tpthread_setname_np(thread.native_handle(), \"mangohud-amdgpu\");\n}\n"
  },
  {
    "path": "src/amdgpu.h",
    "content": "#pragma once\n#include <stdio.h>\n#include <inttypes.h>\n#include <unistd.h>\n#include <string>\n#include \"overlay_params.h\"\n#include <mutex>\n#include <condition_variable>\n#include <vector>\n#include <sys/param.h>\n#include <algorithm>\n#include <atomic>\n#include <thread>\n#include \"gpu_metrics_util.h\"\n\n#ifndef TEST_ONLY\n#include \"gpu_fdinfo.h\"\n#endif\n\n#define NUM_HBM_INSTANCES 4\n#define TEMP_HOTSPOT_BIT 36ull\n#define UPDATE_METRIC_AVERAGE(FIELD) do { int value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } amdgpu_common_metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0)\n#define UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } amdgpu_common_metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0)\n#define UPDATE_METRIC_MAX(FIELD) do { int cur_max = metrics_buffer[0].FIELD; for (size_t s=1; s < METRICS_SAMPLE_COUNT; s++) { cur_max = MAX(cur_max, metrics_buffer[s].FIELD); }; amdgpu_common_metrics.FIELD = cur_max; } while(0)\n#define UPDATE_METRIC_LAST(FIELD) do { amdgpu_common_metrics.FIELD = metrics_buffer[METRICS_SAMPLE_COUNT - 1].FIELD; } while(0)\n#ifdef _WIN32\n#define MAX(x, y) (((x) > (y)) ? (x) : (y))\n#endif\n\nstruct metrics_table_header {\n\tuint16_t\t\t\tstructure_size;\n\tuint8_t\t\t\t\tformat_revision;\n\tuint8_t\t\t\t\tcontent_revision;\n};\n\nstruct gpu_metrics_v1_3 {\n\tstruct metrics_table_header\tcommon_header;\n\n\t/* Temperature */\n\tuint16_t\t\t\ttemperature_edge;\n\tuint16_t\t\t\ttemperature_hotspot;\n\tuint16_t\t\t\ttemperature_mem;\n\tuint16_t\t\t\ttemperature_vrgfx;\n\tuint16_t\t\t\ttemperature_vrsoc;\n\tuint16_t\t\t\ttemperature_vrmem;\n\n\t/* Utilization */\n\tuint16_t\t\t\taverage_gfx_activity;\n\tuint16_t\t\t\taverage_umc_activity; // memory controller\n\tuint16_t\t\t\taverage_mm_activity; // UVD or VCN\n\n\t/* Power/Energy */\n\tuint16_t\t\t\taverage_socket_power;\n\tuint64_t\t\t\tenergy_accumulator;\n\n\t/* Driver attached timestamp (in ns) */\n\tuint64_t\t\t\tsystem_clock_counter;\n\n\t/* Average clocks */\n\tuint16_t\t\t\taverage_gfxclk_frequency;\n\tuint16_t\t\t\taverage_socclk_frequency;\n\tuint16_t\t\t\taverage_uclk_frequency;\n\tuint16_t\t\t\taverage_vclk0_frequency;\n\tuint16_t\t\t\taverage_dclk0_frequency;\n\tuint16_t\t\t\taverage_vclk1_frequency;\n\tuint16_t\t\t\taverage_dclk1_frequency;\n\n\t/* Current clocks */\n\tuint16_t\t\t\tcurrent_gfxclk;\n\tuint16_t\t\t\tcurrent_socclk;\n\tuint16_t\t\t\tcurrent_uclk;\n\tuint16_t\t\t\tcurrent_vclk0;\n\tuint16_t\t\t\tcurrent_dclk0;\n\tuint16_t\t\t\tcurrent_vclk1;\n\tuint16_t\t\t\tcurrent_dclk1;\n\n\t/* Throttle status */\n\tuint32_t\t\t\tthrottle_status;\n\n\t/* Fans */\n\tuint16_t\t\t\tcurrent_fan_speed;\n\n\t/* Link width/speed */\n\tuint16_t\t\t\tpcie_link_width;\n\tuint16_t\t\t\tpcie_link_speed; // in 0.1 GT/s\n\n\tuint16_t\t\t\tpadding;\n\n\tuint32_t\t\t\tgfx_activity_acc;\n\tuint32_t\t\t\tmem_activity_acc;\n\n\tuint16_t\t\t\ttemperature_hbm[NUM_HBM_INSTANCES];\n\n\t/* PMFW attached timestamp (10ns resolution) */\n\tuint64_t\t\t\tfirmware_timestamp;\n\n\t/* Voltage (mV) */\n\tuint16_t\t\t\tvoltage_soc;\n\tuint16_t\t\t\tvoltage_gfx;\n\tuint16_t\t\t\tvoltage_mem;\n\n\tuint16_t\t\t\tpadding1;\n\n\t/* Throttle status (ASIC independent) */\n\tuint64_t\t\t\tindep_throttle_status;\n};\n\nstruct gpu_metrics_v2_3 {\n\tstruct metrics_table_header\tcommon_header;\n\n\t/* Temperature */\n\tuint16_t\t\t\ttemperature_gfx; // gfx temperature on APUs\n\tuint16_t\t\t\ttemperature_soc; // soc temperature on APUs\n\tuint16_t\t\t\ttemperature_core[8]; // CPU core temperature on APUs\n\tuint16_t\t\t\ttemperature_l3[2];\n\n\t/* Utilization */\n\tuint16_t\t\t\taverage_gfx_activity;\n\tuint16_t\t\t\taverage_mm_activity; // UVD or VCN\n\n\t/* Driver attached timestamp (in ns) */\n\tuint64_t\t\t\tsystem_clock_counter;\n\n\t/* Power/Energy */\n\tuint16_t\t\t\taverage_socket_power; // dGPU + APU power on A + A platform\n\tuint16_t\t\t\taverage_cpu_power;\n\tuint16_t\t\t\taverage_soc_power;\n\tuint16_t\t\t\taverage_gfx_power;\n\tuint16_t\t\t\taverage_core_power[8]; // CPU core power on APUs\n\n\t/* Average clocks */\n\tuint16_t\t\t\taverage_gfxclk_frequency;\n\tuint16_t\t\t\taverage_socclk_frequency;\n\tuint16_t\t\t\taverage_uclk_frequency;\n\tuint16_t\t\t\taverage_fclk_frequency;\n\tuint16_t\t\t\taverage_vclk_frequency;\n\tuint16_t\t\t\taverage_dclk_frequency;\n\n\t/* Current clocks */\n\tuint16_t\t\t\tcurrent_gfxclk;\n\tuint16_t\t\t\tcurrent_socclk;\n\tuint16_t\t\t\tcurrent_uclk;\n\tuint16_t\t\t\tcurrent_fclk;\n\tuint16_t\t\t\tcurrent_vclk;\n\tuint16_t\t\t\tcurrent_dclk;\n\tuint16_t\t\t\tcurrent_coreclk[8]; // CPU core clocks\n\tuint16_t\t\t\tcurrent_l3clk[2];\n\n\t/* Throttle status (ASIC dependent) */\n\tuint32_t\t\t\tthrottle_status;\n\n\t/* Fans */\n\tuint16_t\t\t\tfan_pwm;\n\n\tuint16_t\t\t\tpadding[3];\n\n\t/* Throttle status (ASIC independent) */\n\tuint64_t\t\t\tindep_throttle_status;\n\n\t/* Average Temperature */\n\tuint16_t\t\t\taverage_temperature_gfx; // average gfx temperature on APUs\n\tuint16_t\t\t\taverage_temperature_soc; // average soc temperature on APUs\n\tuint16_t\t\t\taverage_temperature_core[8]; // average CPU core temperature on APUs\n\tuint16_t\t\t\taverage_temperature_l3[2];\n};\n\n\nstruct gpu_metrics_v2_4 {\n\tstruct metrics_table_header\tcommon_header;\n\n\t/* Temperature (unit: centi-Celsius) */\n\tuint16_t\t\t\ttemperature_gfx;\n\tuint16_t\t\t\ttemperature_soc;\n\tuint16_t\t\t\ttemperature_core[8];\n\tuint16_t\t\t\ttemperature_l3[2];\n\n\t/* Utilization (unit: centi) */\n\tuint16_t\t\t\taverage_gfx_activity;\n\tuint16_t\t\t\taverage_mm_activity;\n\n\t/* Driver attached timestamp (in ns) */\n\tuint64_t\t\t\tsystem_clock_counter;\n\n\t/* Power/Energy (unit: mW) */\n\tuint16_t\t\t\taverage_socket_power;\n\tuint16_t\t\t\taverage_cpu_power;\n\tuint16_t\t\t\taverage_soc_power;\n\tuint16_t\t\t\taverage_gfx_power;\n\tuint16_t\t\t\taverage_core_power[8];\n\n\t/* Average clocks (unit: MHz) */\n\tuint16_t\t\t\taverage_gfxclk_frequency;\n\tuint16_t\t\t\taverage_socclk_frequency;\n\tuint16_t\t\t\taverage_uclk_frequency;\n\tuint16_t\t\t\taverage_fclk_frequency;\n\tuint16_t\t\t\taverage_vclk_frequency;\n\tuint16_t\t\t\taverage_dclk_frequency;\n\n\t/* Current clocks (unit: MHz) */\n\tuint16_t\t\t\tcurrent_gfxclk;\n\tuint16_t\t\t\tcurrent_socclk;\n\tuint16_t\t\t\tcurrent_uclk;\n\tuint16_t\t\t\tcurrent_fclk;\n\tuint16_t\t\t\tcurrent_vclk;\n\tuint16_t\t\t\tcurrent_dclk;\n\tuint16_t\t\t\tcurrent_coreclk[8];\n\tuint16_t\t\t\tcurrent_l3clk[2];\n\n\t/* Throttle status (ASIC dependent) */\n\tuint32_t\t\t\tthrottle_status;\n\n\t/* Fans */\n\tuint16_t\t\t\tfan_pwm;\n\n\tuint16_t\t\t\tpadding[3];\n\n\t/* Throttle status (ASIC independent) */\n\tuint64_t\t\t\tindep_throttle_status;\n\n\t/* Average Temperature (unit: centi-Celsius) */\n\tuint16_t\t\t\taverage_temperature_gfx;\n\tuint16_t\t\t\taverage_temperature_soc;\n\tuint16_t\t\t\taverage_temperature_core[8];\n\tuint16_t\t\t\taverage_temperature_l3[2];\n\n\t/* Power/Voltage (unit: mV) */\n\tuint16_t\t\t\taverage_cpu_voltage;\n\tuint16_t\t\t\taverage_soc_voltage;\n\tuint16_t\t\t\taverage_gfx_voltage;\n\n\t/* Power/Current (unit: mA) */\n\tuint16_t\t\t\taverage_cpu_current;\n\tuint16_t\t\t\taverage_soc_current;\n\tuint16_t\t\t\taverage_gfx_current;\n};\n\nstruct gpu_metrics_v3_0 {\n\tstruct metrics_table_header\tcommon_header;\n\n\t/* Temperature */\n\t/* gfx temperature on APUs */\n\tuint16_t\t\t\ttemperature_gfx;\n\t/* soc temperature on APUs */\n\tuint16_t\t\t\ttemperature_soc;\n\t/* CPU core temperature on APUs */\n\tuint16_t\t\t\ttemperature_core[16];\n\t/* skin temperature on APUs */\n\tuint16_t\t\t\ttemperature_skin;\n\n\t/* Utilization */\n\t/* time filtered GFX busy % [0-100] */\n\tuint16_t\t\t\taverage_gfx_activity;\n\t/* time filtered VCN busy % [0-100] */\n\tuint16_t\t\t\taverage_vcn_activity;\n\t/* time filtered IPU per-column busy % [0-100] */\n\tuint16_t\t\t\taverage_ipu_activity[8];\n\t/* time filtered per-core C0 residency % [0-100]*/\n\tuint16_t\t\t\taverage_core_c0_activity[16];\n\t/* time filtered DRAM read bandwidth [MB/sec] */\n\tuint16_t\t\t\taverage_dram_reads;\n\t/* time filtered DRAM write bandwidth [MB/sec] */\n\tuint16_t\t\t\taverage_dram_writes;\n\t/* time filtered IPU read bandwidth [MB/sec] */\n\tuint16_t\t\t\taverage_ipu_reads;\n\t/* time filtered IPU write bandwidth [MB/sec] */\n\tuint16_t\t\t\taverage_ipu_writes;\n\n\t/* Driver attached timestamp (in ns) */\n\tuint64_t\t\t\tsystem_clock_counter;\n\n\t/* Power/Energy */\n\t/* time filtered power used for PPT/STAPM [APU+dGPU] [mW] */\n\tuint32_t\t\t\taverage_socket_power;\n\t/* time filtered IPU power [mW] */\n\tuint16_t\t\t\taverage_ipu_power;\n\t/* time filtered APU power [mW] */\n\tuint32_t\t\t\taverage_apu_power;\n\t/* time filtered GFX power [mW] */\n\tuint32_t\t\t\taverage_gfx_power;\n\t/* time filtered dGPU power [mW] */\n\tuint32_t\t\t\taverage_dgpu_power;\n\t/* time filtered sum of core power across all cores in the socket [mW] */\n\tuint32_t\t\t\taverage_all_core_power;\n\t/* calculated core power [mW] */\n\tuint16_t\t\t\taverage_core_power[16];\n\t/* time filtered total system power [mW] */\n\tuint16_t\t\t\taverage_sys_power;\n\t/* maximum IRM defined STAPM power limit [mW] */\n\tuint16_t\t\t\tstapm_power_limit;\n\t/* time filtered STAPM power limit [mW] */\n\tuint16_t\t\t\tcurrent_stapm_power_limit;\n\n\t/* time filtered clocks [MHz] */\n\tuint16_t\t\t\taverage_gfxclk_frequency;\n\tuint16_t\t\t\taverage_socclk_frequency;\n\tuint16_t\t\t\taverage_vpeclk_frequency;\n\tuint16_t\t\t\taverage_ipuclk_frequency;\n\tuint16_t\t\t\taverage_fclk_frequency;\n\tuint16_t\t\t\taverage_vclk_frequency;\n\tuint16_t\t\t\taverage_uclk_frequency;\n\tuint16_t\t\t\taverage_mpipu_frequency;\n\n\t/* Current clocks */\n\t/* target core frequency [MHz] */\n\tuint16_t\t\t\tcurrent_coreclk[16];\n\t/* CCLK frequency limit enforced on classic cores [MHz] */\n\tuint16_t\t\t\tcurrent_core_maxfreq;\n\t/* GFXCLK frequency limit enforced on GFX [MHz] */\n\tuint16_t\t\t\tcurrent_gfx_maxfreq;\n\n\t/* Throttle Residency (ASIC dependent) */\n\tuint32_t\t\t\tthrottle_residency_prochot;\n\tuint32_t\t\t\tthrottle_residency_spl;\n\tuint32_t\t\t\tthrottle_residency_fppt;\n\tuint32_t\t\t\tthrottle_residency_sppt;\n\tuint32_t\t\t\tthrottle_residency_thm_core;\n\tuint32_t\t\t\tthrottle_residency_thm_gfx;\n\tuint32_t\t\t\tthrottle_residency_thm_soc;\n\n\t/* Metrics table alpha filter time constant [us] */\n\tuint32_t\t\t\ttime_filter_alphavalue;\n};\n\nstruct amdgpu_files\n{\n    FILE *vram_total;\n    FILE *vram_used;\n    /* The following can be NULL, in that case we're using the gpu_metrics node */\n    FILE *busy;\n    FILE *temp;\n    FILE *junction_temp;\n    FILE *memory_temp;\n    FILE *core_clock;\n    FILE *memory_clock;\n    FILE *power_usage;\n    FILE *power_limit;\n    FILE *gtt_used;\n    FILE *fan;\n    FILE *gpu_voltage_soc;\n};\n\n/* This structure is used to communicate the latest values of the amdgpu metrics.\n * The direction of communication is amdgpu_polling_thread -> amdgpu_get_metrics().\n */\nstruct amdgpu_common_metrics {\n\t/* Load level: averaged across the sampling period */\n\tuint16_t gpu_load_percent;\n\t// uint16_t mem_load_percent;\n\n\t/* Power usage: averaged across the sampling period */\n\tfloat average_gfx_power_w;\n\tfloat average_cpu_power_w;\n\n\t/* Clocks: latest value of the clock */\n\tuint16_t current_gfxclk_mhz;\n\tuint16_t current_uclk_mhz;\n\n\t/* Temperatures: maximum values over the sampling period */\n\tuint16_t soc_temp_c;\n\tuint16_t gpu_temp_c;\n\tuint16_t apu_cpu_temp_c;\n\n\t/* throttling status */\n\tbool is_power_throttled;\n\tbool is_current_throttled;\n\tbool is_temp_throttled;\n\tbool is_other_throttled;\n\n\tuint16_t fan_speed;\n};\n\nextern std::string metrics_path;\n\nclass AMDGPU {\n\tpublic:\n\t\tbool is_apu = false;\n\t\tstd::shared_ptr<Throttling> throttling;\n\n    \tAMDGPU(std::string pci_dev, uint32_t device_id, uint32_t vendor_id);\n\n\t\t~AMDGPU() {\n\t\t\tstop_thread = true;\n\t\t\tif (thread.joinable())\n\t\t\t\tthread.join();\n\t\t}\n\n\t\tvoid get_instant_metrics(struct amdgpu_common_metrics *metrics);\n\t\tvoid get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT],\n\t\t\t\t\t\t\t\t  bool &gpu_load_needs_dividing);\n\n        gpu_metrics copy_metrics() {\n            std::lock_guard<std::mutex> lock(metrics_mutex);\n            return metrics;\n        };\n\n        void pause() {\n            paused = true;\n            cond_var.notify_one();\n        };\n\n        void resume() {\n            paused = false;\n            cond_var.notify_one();\n        }\n\n\tprivate:\n\t\tstd::string pci_dev;\n\t\tstd::string gpu_metrics_path;\n\t\tuint32_t device_id;\n\t\tuint32_t vendor_id;\n\t\tstd::condition_variable amdgpu_c;\n\t\tstd::thread thread;\n\t\tstruct amdgpu_files sysfs_nodes = {};\n\t\tbool gpu_metrics_is_valid = false;\n\t\tstd::condition_variable cond_var;\n\t\tstd::atomic<bool> stop_thread{false};\n        std::atomic<bool> paused{false};\n\t\tstd::mutex metrics_mutex;\n\t\tgpu_metrics metrics;\n\t\tstruct amdgpu_common_metrics amdgpu_common_metrics;\n\t\tstruct gpu_metrics_v3_0 previous_metrics{};\n\t\t#define V3_THROTTLING_DELTA(name) \\\n\t\t((amdgpu_metrics)->throttle_residency_##name - (previous_metrics).throttle_residency_##name)\n\n#ifndef TEST_ONLY\n\t\tstd::unique_ptr<GPU_fdinfo> fdinfo_helper;\n#endif\n\n\t\tvoid get_sysfs_metrics();\n\t\tvoid metrics_polling_thread();\n};\n"
  },
  {
    "path": "src/app/control.c",
    "content": "#include <sys/ipc.h>\n#include <sys/msg.h>\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdbool.h>\n\n#include \"mangoapp_proto.h\"\n\nstatic void help_and_quit() {\n    fprintf(stderr, \"Usage: mangohudctl [set|toggle] attribute [value]\\n\");\n    fprintf(stderr, \"       mangohudctl reload-cfg\\n\");\n    fprintf(stderr, \"Attributes:\\n\");\n    fprintf(stderr, \"   no_display      hides or shows hud\\n\");\n    fprintf(stderr, \"   log_session     handles logging status\\n\");\n    fprintf(stderr, \"   reload_config   reloads the config\\n\");\n    fprintf(stderr, \"Accepted values:\\n\");\n    fprintf(stderr, \"   true\\n\");\n    fprintf(stderr, \"   false\\n\");\n    fprintf(stderr, \"   1\\n\");\n    fprintf(stderr, \"   0\\n\");\n    exit(1);\n}\n\nstatic bool str_to_bool(const char *value)\n{\n    if (strcasecmp(value, \"true\") == 0 || strcmp(value, \"1\") == 0)\n        return true;\n    else if (strcasecmp(value, \"false\") == 0 || strcmp(value, \"0\") == 0)\n        return false;\n\n    /* invalid boolean, display a nice error message saying that */\n    fprintf(stderr, \"The value '%s' is not an accepted boolean. Use 0/1 or true/false\\n\", value);\n    exit(1);\n}\n\nint main(int argc, char *argv[])\n{\n    /* Set up message queue */\n    int key = ftok(\"mangoapp\", 65);\n    int msgid = msgget(key, 0666 | IPC_CREAT);\n    /* Create the message that we will send to mangohud */\n    struct mangoapp_ctrl_msgid1_v1 ctrl_msg = {\n        .hdr.msg_type = 2,\n        .hdr.ctrl_msg_type = 1,\n        .hdr.version = 1,\n    };\n    uint8_t value;\n\n    if (argc <= 2)\n        help_and_quit();\n\n    if (strcmp(argv[1], \"set\") == 0) {\n        if (argc != 4)\n            help_and_quit();\n\n        value = str_to_bool(argv[3]) ? 1 : 2;\n    } else if (strcmp(argv[1], \"toggle\") == 0) {\n        if (argc != 3)\n            help_and_quit();\n\n        value = 3;\n    } else {\n        help_and_quit();\n    }\n\n    if (strcmp(argv[2], \"no_display\") == 0)\n        ctrl_msg.no_display = value;\n    else if (strcmp(argv[2], \"log_session\") == 0)\n        ctrl_msg.log_session = value;\n    else if (strcmp(argv[2], \"reload_config\") == 0)\n        ctrl_msg.reload_config = value;\n    else\n        help_and_quit();\n\n    msgsnd(msgid, &ctrl_msg, sizeof(struct mangoapp_ctrl_msgid1_v1), IPC_NOWAIT);\n\n    return 0;\n}\n"
  },
  {
    "path": "src/app/main.cpp",
    "content": "// Dear ImGui: standalone example application for GLFW + OpenGL 3, using programmable pipeline\n// (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)\n// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.\n// Read online: https://github.com/ocornut/imgui/tree/master/docs\n\n#include <sys/ipc.h>\n#include <sys/msg.h>\n\n#include \"imgui.h\"\n#include \"imgui_impl_glfw.h\"\n#include \"imgui_impl_opengl3.h\"\n#include <stdio.h>\n#include <thread>\n#include <unistd.h>\n#include \"../overlay.h\"\n#include \"notify.h\"\n#include \"mangoapp.h\"\n#include \"mangoapp_proto.h\"\n#include <GLFW/glfw3.h>\n#ifdef __linux__\n#include \"implot.h\"\n#endif\n\n#define GLFW_EXPOSE_NATIVE_X11\n#include <GLFW/glfw3native.h>\n#include <X11/Xatom.h>\n#include <X11/Xlib.h>\n#include <poll.h>\n\nusing namespace std;\n\nstatic void glfw_error_callback(int error, const char* description)\n{\n    fprintf(stderr, \"Glfw Error %d: %s\\n\", error, description);\n}\n\nswapchain_stats sw_stats {};\noverlay_params params {};\nstatic ImVec2 window_size;\nstatic uint32_t vendorID;\nstatic std::string deviceName;\nstatic notify_thread notifier;\nstatic int msgid;\nstatic bool mangoapp_paused = false;\nstd::mutex mangoapp_m;\nstd::condition_variable mangoapp_cv;\nstatic uint8_t raw_msg[1024] = {0};\nstatic uint32_t screenWidth, screenHeight;\nstatic std::atomic_bool g_x_dead{false};\n\nstatic bool x_connection_ok(Display* dpy) {\n    if (!dpy)\n        return false;\n\n    int fd = XConnectionNumber(dpy);\n    if (fd < 0)\n        return false;\n\n    pollfd p{fd, 0, 0};\n    if (poll(&p, 1, 0) < 0)\n        return false;\n\n    return (p.revents & (POLLERR | POLLHUP | POLLNVAL)) == 0;\n}\n\nstatic unsigned int get_prop(const char* propName){\n    if (g_x_dead.load())\n        return -1;\n\n    Display *x11_display = glfwGetX11Display();\n    // Make sure Xorg display is still there before continuing\n    if (!x_connection_ok(x11_display)) {\n        g_x_dead.store(true);\n        return -1;\n    }\n\n    Atom gamescope_focused = XInternAtom(x11_display, propName, false);\n    auto scr = DefaultScreen(x11_display);\n    auto root = RootWindow(x11_display, scr);\n    Atom actual;\n    int format;\n    unsigned long n, left;\n    uint64_t *data;\n    int result = XGetWindowProperty(x11_display, root, gamescope_focused, 0L, 1L, false,\n                            XA_CARDINAL, &actual, &format,\n                            &n, &left, ( unsigned char** )&data);\n\n    if (result == Success && data != NULL){\n        unsigned int i;\n        memcpy(&i, data, sizeof(unsigned int));\n        XFree((void *) data);\n        return i;\n    }\n    return -1;\n}\n\nstatic void ctrl_thread(){\n    while (1){\n        const struct mangoapp_ctrl_msgid1_v1 *mangoapp_ctrl_v1 = (const struct mangoapp_ctrl_msgid1_v1*) raw_msg;\n        memset(raw_msg, 0, sizeof(raw_msg));\n        msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 2, 0);\n        switch (mangoapp_ctrl_v1->log_session) {\n            case 0:\n                // Keep as-is\n                break;\n            case 1:\n                if (!logger->is_active())\n                    logger->start_logging();\n                break;\n            case 2:\n                if (logger->is_active())\n                    logger->stop_logging();\n                break;\n            case 3:\n                logger->is_active() ? logger->stop_logging() : logger->start_logging();\n                break;\n        }\n        switch (mangoapp_ctrl_v1->reload_config) {\n            case 0:\n                break;\n            case 1:\n                parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n                break;\n            case 2:\n                break;\n            case 3:\n                parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n                break;\n        }\n        {\n            std::lock_guard<std::mutex> lk(mangoapp_m);\n            auto real_params = get_params();\n            switch (mangoapp_ctrl_v1->no_display){\n                case 0:\n                    // Keep as-is\n                    break;\n                case 1:\n                    real_params->no_display = 1;\n                    break;\n                case 2:\n                    real_params->no_display = 0;\n                    break;\n                case 3:\n                    real_params->no_display ? real_params->no_display = 0 : real_params->no_display = 1;\n                    break;\n            }\n        }\n        mangoapp_cv.notify_one();\n    }\n}\n\nbool new_frame = false;\n\nstatic void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){\n    if (app_frametime_ns != uint64_t(-1))\n    {\n        float app_frametime_ms = app_frametime_ns / 1000000.f;\n        HUDElements.gamescope_debug_app.push_back(app_frametime_ms);\n        if (HUDElements.gamescope_debug_app.size() > 200)\n            HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin());\n    }\n\n    float latency_ms = latency_ns / 1000000.f;\n    if (latency_ns == uint64_t(-1))\n        latency_ms = -1;\n    HUDElements.gamescope_debug_latency.push_back(latency_ms);\n    if (HUDElements.gamescope_debug_latency.size() > 200)\n        HUDElements.gamescope_debug_latency.erase(HUDElements.gamescope_debug_latency.begin());\n}\n\nstatic void msg_read_thread(){\n    for (size_t i = 0; i < 200; i++){\n        HUDElements.gamescope_debug_app.push_back(0);\n        HUDElements.gamescope_debug_latency.push_back(0);\n    }\n    int key = ftok(\"mangoapp\", 65);\n    msgid = msgget(key, 0666 | IPC_CREAT);\n    // uint32_t previous_pid = 0;\n    const struct mangoapp_msg_header *hdr = (const struct mangoapp_msg_header*) raw_msg;\n    const struct mangoapp_msg_v1 *mangoapp_v1 = (const struct mangoapp_msg_v1*) raw_msg;\n\n    uint32_t previous_game_pid = 0;\n\n    while (1){\n        // make sure that the message recieved is compatible\n        // and that we're not trying to use variables that don't exist (yet)\n        size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0);\n        if (msg_size != size_t(-1))\n        {\n            if (hdr->version == 1){\n                if (msg_size > offsetof(struct mangoapp_msg_v1, pid)) {\n                    HUDElements.g_gamescopePid = mangoapp_v1->pid;\n\n                    if (previous_game_pid != mangoapp_v1->pid) {\n                        previous_game_pid = mangoapp_v1->pid;\n                        check_for_vkbasalt_and_gamemode();\n                    }\n                }\n\n                if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){\n                    auto real_params = get_params();\n                    bool should_new_frame = false;\n                    if (mangoapp_v1->visible_frametime_ns != ~(0lu) && (!real_params->no_display || logger->is_active())) {\n                        update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns);\n                        should_new_frame = true;\n                    }\n\n                    if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){\n                        HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale;\n                        if (real_params->fsr_steam_sharpness < 0)\n                            HUDElements.g_fsrSharpness = mangoapp_v1->fsrSharpness;\n                        else\n                        HUDElements.g_fsrSharpness = real_params->fsr_steam_sharpness - mangoapp_v1->fsrSharpness;\n                    }\n                    if (!real_params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam]){\n                        steam_focused = get_prop(\"GAMESCOPE_FOCUSED_APP_GFX\") == 769;\n                    } else {\n                        steam_focused = false;\n                    }\n\n                    if (msg_size > offsetof(mangoapp_msg_v1, latency_ns))\n                        gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns);\n\n                    if (should_new_frame)\n                    {\n                        {\n                            std::unique_lock<std::mutex> lk(mangoapp_m);\n                            new_frame = true;\n                        }\n                        mangoapp_cv.notify_one();\n                        screenWidth = mangoapp_v1->outputWidth;\n                        screenHeight = mangoapp_v1->outputHeight;\n                    }\n                }\n            } else {\n                printf(\"Unsupported mangoapp struct version: %i\\n\", hdr->version);\n            }\n        }\n        else\n        {\n            printf(\"mangoapp: msgrcv returned -1 with error %d - %s\\n\", errno, strerror(errno));\n        }\n    }\n}\n\nstatic const char *GamescopeOverlayProperty = \"GAMESCOPE_EXTERNAL_OVERLAY\";\n\nstatic GLFWwindow* init(const char* glsl_version){\n    init_spdlog();\n    GLFWwindow *window = glfwCreateWindow(1280, 800, \"mangoapp overlay window\", NULL, NULL);\n    Display *x11_display = glfwGetX11Display();\n    Window x11_window = glfwGetX11Window(window);\n    if (x11_window && x11_display)\n    {\n        // Set atom for gamescope to render as an overlay.\n        Atom overlay_atom = XInternAtom (x11_display, GamescopeOverlayProperty, False);\n        uint32_t value = 1;\n        XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropertyNewValue, (unsigned char *)&value, 1);\n    }\n\n    glfwMakeContextCurrent(window);\n    glfwSwapInterval(1); // Enable vsync\n    ImGui::CreateContext();\n#ifdef __linux__\n    ImPlot::CreateContext();\n#endif\n    ImGuiIO& io = ImGui::GetIO(); (void)io;\n    io.IniFilename = NULL;\n    ImGui::StyleColorsDark();\n    ImGui_ImplGlfw_InitForOpenGL(window, true);\n    ImGui_ImplOpenGL3_Init(glsl_version);\n    return window;\n}\n\nstatic void shutdown(GLFWwindow* window){\n    ImGui_ImplOpenGL3_Shutdown();\n    ImGui_ImplGlfw_Shutdown();\n    ImGui::DestroyContext();\n    glfwDestroyWindow(window);\n}\n\nstatic void get_atom_info(){\n    HUDElements.hdr_status = get_prop(\"GAMESCOPE_COLOR_APP_WANTS_HDR_FEEDBACK\");\n    HUDElements.refresh = get_prop(\"GAMESCOPE_DISPLAY_REFRESH_RATE_FEEDBACK\");\n}\n\nstatic bool render(GLFWwindow* window, overlay_params& real_params) {\n    if (HUDElements.colors.update)\n        HUDElements.convert_colors(params);\n\n    if (sw_stats.font_params_hash != params.font_params_hash)\n    {\n        sw_stats.font_params_hash = params.font_params_hash;\n        create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary);\n        ImGui_ImplOpenGL3_CreateFontsTexture();\n    }\n    ImGui_ImplGlfw_NewFrame();\n    ImGui_ImplOpenGL3_NewFrame();\n    ImGui::NewFrame();\n    overlay_new_frame(real_params);\n    position_layer(sw_stats, real_params, window_size);\n    render_imgui(sw_stats, real_params, window_size, true);\n    get_atom_info();\n    overlay_end_frame();\n    static bool window_size_changed = false;\n    int w, h;\n    glfwGetWindowSize(window, &w, &h);\n    window_size_changed = w != window_size.x || h != window_size.y;\n    if (real_params.enabled[OVERLAY_PARAM_ENABLED_horizontal])\n    // trying to reduce height will break direct scanout in some cases\n    // just leave it for now, we'll revisit it in server\n    glfwSetWindowSize(window, screenWidth, screenHeight);\n\n    ImGui::EndFrame();\n\n    return window_size_changed;\n}\n\nint main(int, char**)\n{\n    XInitThreads();\n\n    // Setup window\n    glfwSetErrorCallback(glfw_error_callback);\n    if (!glfwInit())\n        return 1;\n\n    const char* glsl_version = \"#version 130\";\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);\n\n    glfwWindowHint(GLFW_RESIZABLE, 1);\n    glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1);\n    glfwWindowHint(GLFW_DEPTH_BITS,   0);\n    glfwWindowHint(GLFW_STENCIL_BITS, 0);\n\n    // Create window with graphics context\n    GLFWwindow* window = init(glsl_version);\n\n    Display *x11_display = glfwGetX11Display();\n    Window x11_window = glfwGetX11Window(window);\n    Atom overlay_atom = XInternAtom (x11_display, GamescopeOverlayProperty, False);\n\n    // Setup Platform/Renderer backends\n    int control_client = -1;\n    parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n    create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary);\n    HUDElements.convert_colors(params);\n    init_cpu_stats(params);\n    notifier.params = &params;\n    start_notifier(notifier);\n    auto real_params = get_params();\n    window_size = ImVec2(real_params->width, real_params->height);\n    deviceName = (char*)glGetString(GL_RENDERER);\n    sw_stats.deviceName = deviceName;\n    SPDLOG_DEBUG(\"mangoapp deviceName: {}\", deviceName);\n    #define GLX_RENDERER_VENDOR_ID_MESA 0x8183\n    auto pfn_glXQueryCurrentRendererIntegerMESA = (Bool (*)(int, unsigned int*)) (glfwGetProcAddress(\"glXQueryCurrentRendererIntegerMESA\"));\n    // This will return 0x0 vendorID on NVIDIA so just go to else\n    if (pfn_glXQueryCurrentRendererIntegerMESA && vendorID != 0x0) {\n        pfn_glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA, &vendorID);\n        SPDLOG_DEBUG(\"mangoapp vendorID: {:#x}\", vendorID);\n    } else {\n        if (deviceName.find(\"Radeon\") != std::string::npos\n        || deviceName.find(\"AMD\") != std::string::npos){\n            vendorID = 0x1002;\n        } else if (deviceName.find(\"Intel\") != std::string::npos) {\n            vendorID = 0x8086;\n        } else {\n            vendorID = 0x10de;\n        }\n    }\n\n    HUDElements.vendorID = vendorID;\n    init_system_info();\n    sw_stats.engine = EngineTypes::GAMESCOPE;\n    std::thread(msg_read_thread).detach();\n    std::thread(ctrl_thread).detach();\n    if (!logger) logger = std::make_unique<Logger>(&params);\n    Atom noFocusAtom = XInternAtom(x11_display, \"GAMESCOPE_NO_FOCUS\", False);\n    uint32_t value = 1;\n    XChangeProperty(x11_display, x11_window, noFocusAtom, XA_CARDINAL, 32,\n                    PropModeReplace, (unsigned char *)&value, 1);\n    // Main loop\n    while (!glfwWindowShouldClose(window)){\n        real_params = get_params();\n        check_keybinds(*real_params);\n        if (!real_params->no_display && new_frame){\n            if (mangoapp_paused){\n                glfwShowWindow(window);\n                render(window, *real_params);\n                uint32_t value = 1;\n                XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1);\n                XSync(x11_display, 0);\n                mangoapp_paused = false;\n                // resume all GPU threads\n                if (gpus)\n                    for (auto gpu : gpus->available_gpus)\n                        gpu->resume();\n            }\n\n            {\n                if (render(window, *real_params)) {\n                    // If we need to resize our window, give it another couple of rounds for the\n                    // stupid display size stuff to propagate through ImGUI (using NDC and scaling\n                    // in GL makes me a very unhappy boy.)\n                    render(window, *real_params);\n                    render(window, *real_params);\n                }\n\n                if (real_params->control >= 0) {\n                    control_client_check(real_params->control, control_client, deviceName);\n                    process_control_socket(control_client, params);\n                }\n            }\n            // Rendering\n            ImGui::Render();\n            glEnable(GL_DEPTH_TEST);\n            glEnable(GL_BLEND);\n            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n            glClearColor(0, 0, 0, 0);\n            glClear(GL_COLOR_BUFFER_BIT);\n            ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());\n\n            glfwSwapBuffers(window);\n        } else if (!mangoapp_paused) {\n            glClearColor(0, 0, 0, 0);\n            glClear(GL_COLOR_BUFFER_BIT);\n            glfwSwapBuffers(window);\n            glfwHideWindow(window);\n            uint32_t value = 0;\n            XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1);\n            XSync(x11_display, 0);\n            mangoapp_paused = true;\n            // pause all GPUs threads\n            if (gpus)\n                for (auto gpu : gpus->available_gpus)\n                    gpu->pause();\n\n            // If mangoapp is hidden, using mangoapp_cv.wait() causes a hang.\n            // Because of this hang, we can't detect if the user presses R_SHIFT + F12,\n            // which prevents mangoapp from being unhidden.\n            // To address this, replace mangoapp_cv.wait() with sleep().\n            //\n            // If severe power usage issues arise, find an alternative solution.\n\n            // std::unique_lock<std::mutex> lk(mangoapp_m);\n            // mangoapp_cv.wait(lk, []{return !get_params()->no_display;});\n        } else {\n            usleep(500000);\n        }\n    }\n\n    // Cleanup\n    shutdown(window);\n\n    glfwTerminate();\n\n    return 0;\n}\n"
  },
  {
    "path": "src/app/mangoapp.h",
    "content": "#pragma once\n#include <stdint.h>\n#include <mutex>\n#include <condition_variable>\n#include <vector>\n\nextern std::mutex mangoapp_m;\nextern std::condition_variable mangoapp_cv;\n"
  },
  {
    "path": "src/app/mangoapp_proto.h",
    "content": "#include <stdint.h>\n\nstruct mangoapp_msg_header {\n    long msg_type;  // Message queue ID, never change\n    uint32_t version;  /* for major changes in the way things work */\n} __attribute__((packed));\n\nstruct mangoapp_msg_v1 {\n    struct mangoapp_msg_header hdr;\n\n    uint32_t pid;\n    uint64_t visible_frametime_ns;\n    uint8_t fsrUpscale;\n    uint8_t fsrSharpness;\n    // For debugging\n    uint64_t app_frametime_ns;\n    uint64_t latency_ns;\n    uint32_t outputWidth;\n    uint32_t outputHeight;\n    // WARNING: Always ADD fields, never remove or repurpose fields\n} __attribute__((packed));\n\nstruct mangoapp_ctrl_header {\n    long msg_type;  // Message queue ID, never change\n    uint32_t ctrl_msg_type; /* This is a way to share the same thread between multiple types of messages */\n    uint32_t version;  /* version of the message type, for backwards incompatible changes */\n} __attribute__((packed));\n\nstruct mangoapp_ctrl_msgid1_v1 {\n    struct mangoapp_ctrl_header hdr;\n\n    // When a field is set to 0, it should always mean \"ignore\" or \"no changes\"\n    uint8_t no_display;      // 0x0 = ignore; 0x1 = disable; 0x2 = enable; 0x3 = toggle\n    uint8_t log_session;     // 0x0 = ignore; 0x1 = start a session; 0x2 = stop the current session; 0x3 = toggle logging\n    char log_session_name[64]; // if byte 0 is NULL, ignore. Needs to be set when starting/toggling a session if we want to override the default name\n    uint8_t reload_config;\n\n    // WARNING: Always ADD fields, never remove or repurpose fields\n} __attribute__((packed));\n"
  },
  {
    "path": "src/battery.cpp",
    "content": "#include <spdlog/spdlog.h>\n#include <filesystem.h>\n#include \"battery.h\"\n\nnamespace fs = ghc::filesystem;\nusing namespace std;\n\nvoid BatteryStats::numBattery() {\n    int batteryCount = 0;\n    if (!fs::exists(\"/sys/class/power_supply/\")) {\n         batteryCount = 0;\n    }\n    fs::path path(\"/sys/class/power_supply/\");\n    for (auto& p : fs::directory_iterator(path)) {\n        string fileName = p.path().filename();\n        if (fileName.find(\"BAT\") != std::string::npos) {\n            battPath[batteryCount] = p.path();\n            batteryCount += 1;\n        }\n    }\n    batt_count = batteryCount;\n    batt_check = true;\n}\n\nvoid BatteryStats::update() {\n    if (!batt_check) {\n        numBattery();\n        if (batt_count == 0) {\n            SPDLOG_ERROR(\"No battery found\");\n        }\n    }\n\n     if (batt_count > 0) {\n        current_watt = getPower();\n        current_percent = getPercent();\n        remaining_time = getTimeRemaining();\n    }\n}\n\nfloat BatteryStats::getPercent()\n{\n    float charge_n = 0;\n    float charge_f = 0;\n    for(int i = 0; i < batt_count; i++) {\n        string syspath = battPath[i];\n        string charge_now = syspath + \"/charge_now\";\n        string charge_full = syspath + \"/charge_full\";\n        string energy_now = syspath + \"/energy_now\";\n        string energy_full = syspath + \"/energy_full\";\n        string capacity = syspath + \"/capacity\";\n\n        if (fs::exists(charge_now)) {\n            std::ifstream input(charge_now);\n            std::string line;\n            if(std::getline(input, line)) {\n                charge_n += (stof(line) / 1000000);\n            }\n            std::ifstream input2(charge_full);\n            if(std::getline(input2, line)) {\n                charge_f += (stof(line) / 1000000);\n            }\n        }\n\n        else if (fs::exists(energy_now)) {\n            std::ifstream input(energy_now);\n            std::string line;\n            if(std::getline(input, line)) {\n                charge_n += (stof(line) / 1000000);\n            }\n            std::ifstream input2(energy_full);\n            if(std::getline(input2, line)) {\n                charge_f += (stof(line) / 1000000);\n            }\n        }\n\n        else {\n            // using /sys/class/power_supply/BAT*/capacity\n            // No way to get an accurate reading just average the percents if mutiple batteries\n            std::ifstream input(capacity);\n            std::string line;\n            if(std::getline(input, line)) {\n                charge_n += stof(line) / 100;\n                charge_f = batt_count;\n            }\n        }\n    }\n    return (charge_n / charge_f) * 100;\n}\n\nfloat BatteryStats::getPower() {\n    float power_w = 0.0f;\n\n    for (int i = 0; i < batt_count; i++) {\n        string syspath = battPath[i];\n        string current_now = syspath + \"/current_now\";\n        string voltage_now = syspath + \"/voltage_now\";\n        string power_now = syspath + \"/power_now\";\n        string status = syspath + \"/status\";\n\n        {\n            std::ifstream input(status);\n            std::string line;\n            if (std::getline(input, line)) {\n                current_status = line;\n                state[i] = current_status;\n            }\n        }\n\n        if (state[i] == \"Charging\" || state[i] == \"Unknown\" || state[i] == \"Full\") {\n            // TODO if we have multiple batteries, we will return 0 if just one of them is charging\n            return 0.0f;\n        }\n\n        // Prefer power_now (µW) when available.\n        if (fs::exists(power_now)) {\n            std::ifstream input(power_now);\n            std::string line;\n            if (std::getline(input, line)) {\n                power_w += std::fabs(stof(line)) / 1000000.0f;\n            }\n            continue;\n        }\n\n        if (fs::exists(current_now) && fs::exists(voltage_now)) {\n            float i_ua = 0.0f;\n            float v_uv = 0.0f;\n\n            {\n                std::ifstream input(current_now);\n                std::string line;\n                if (std::getline(input, line)) {\n                    i_ua = stof(line);\n                }\n            }\n            {\n                std::ifstream input(voltage_now);\n                std::string line;\n                if (std::getline(input, line)) {\n                    v_uv = stof(line);\n                }\n            }\n\n            power_w += (std::fabs(i_ua) * std::fabs(v_uv)) * 1e-12f;\n        }\n    }\n\n    return power_w;\n}\n\nfloat BatteryStats::getTimeRemaining() {\n    float current = 0.0f;\n    float charge = 0.0f;\n\n    for (int i = 0; i < batt_count; i++) {\n        string syspath = battPath[i];\n        string current_now = syspath + \"/current_now\";\n        string charge_now = syspath + \"/charge_now\";\n        string energy_now = syspath + \"/energy_now\";\n        string voltage_now = syspath + \"/voltage_now\";\n        string power_now = syspath + \"/power_now\";\n\n        if (fs::exists(current_now)) {\n            std::ifstream input(current_now);\n            std::string line;\n            if (std::getline(input, line)) {\n                current_now_vec.push_back(std::fabs(stof(line)));\n            }\n        } else if (fs::exists(power_now) && fs::exists(voltage_now)) {\n            float voltage = 0.0f;\n            float power = 0.0f;\n\n            {\n                std::ifstream input_voltage(voltage_now);\n                std::string line;\n                if (std::getline(input_voltage, line)) {\n                    voltage = stof(line);\n                }\n            }\n            {\n                std::ifstream input_power(power_now);\n                std::string line;\n                if (std::getline(input_power, line)) {\n                    power = stof(line);\n                }\n            }\n\n            if (voltage > 0.0f) {\n                // (µW / µV) = µA\n                current_now_vec.push_back(std::fabs(power) / voltage);\n            }\n        }\n\n        if (fs::exists(charge_now)) {\n            std::ifstream input(charge_now);\n            std::string line;\n            if (std::getline(input, line)) {\n                charge += stof(line);\n            }\n        } else if (fs::exists(energy_now) && fs::exists(voltage_now)) {\n            float energy = 0.0f;\n            float voltage = 0.0f;\n\n            {\n                std::ifstream input_energy(energy_now);\n                std::string line;\n                if (std::getline(input_energy, line)) {\n                    energy = stof(line);\n                }\n            }\n            {\n                std::ifstream input_voltage(voltage_now);\n                std::string line;\n                if (std::getline(input_voltage, line)) {\n                    voltage = stof(line);\n                }\n            }\n\n            if (voltage > 0.0f) {\n                // (µWh / µV) = µAh\n                charge += energy / voltage;\n            }\n        }\n\n        if (current_now_vec.size() > 25) {\n            current_now_vec.erase(current_now_vec.begin());\n        }\n    }\n\n    if (current_now_vec.empty()) {\n        return 0.0f;\n    }\n\n    for (const auto& current_now_sample : current_now_vec) {\n        current += current_now_sample;\n    }\n    current /= static_cast<float>(current_now_vec.size());\n\n    if (current <= 0.0f) {\n        return 0.0f;\n    }\n\n    return charge / current;\n}\n\nBatteryStats Battery_Stats;\n"
  },
  {
    "path": "src/battery.h",
    "content": "#pragma once\n#include <string>\n\nclass BatteryStats{\n    public:\n        void numBattery();\n        void update();\n        float getPower();\n        float getPercent();\n        float getTimeRemaining();\n        std::string battPath[2];\n        float current_watt = 0;\n        float current_percent = 0;\n        float remaining_time = 0;\n        std::string current_status;\n        std::string state [2];\n        int batt_count=0;\n        bool batt_check = false;\n        std::vector<float> current_now_vec = {};\n};\n\nextern BatteryStats Battery_Stats;\n"
  },
  {
    "path": "src/blacklist.cpp",
    "content": "#include <vector>\n#include <string>\n#include <algorithm>\n#include <spdlog/spdlog.h>\n#include <filesystem.h>\n\n#include \"blacklist.h\"\n#include \"string_utils.h\"\n#include \"file_utils.h\"\n\nnamespace fs = ghc::filesystem;\nstd::string global_proc_name;\nstd::string global_engine_name;\n\nstatic std::string get_proc_name() {\n   // Note: It is possible to use GNU program_invocation_short_name.\n   const std::string proc_name = get_wine_exe_name(/*keep_ext=*/true);\n   if (!proc_name.empty()) {\n       return proc_name;\n   }\n   return get_basename(get_exe_path());\n}\n\nstatic  std::vector<std::string> blacklist {\n    \"Amazon Games UI.exe\",\n    \"Battle.net.exe\",\n    \"BethesdaNetLauncher.exe\",\n    \"EADesktop.exe\",\n    \"EALauncher.exe\",\n    \"EpicGamesLauncher.exe\",\n    \"EpicWebHelper.exe\",\n    \"explorer.exe\",\n    \"ffxivlauncher.exe\",\n    \"ffxivlauncher64.exe\",\n    \"GalaxyClient.exe\",\n    \"gamescope\",\n    \"GardenGate_Launcher.exe\",\n    \"gldriverquery\",\n    \"halloy\",\n    \"IGOProxy.exe\",\n    \"IGOProxy64.exe\",\n    \"iexplore.exe\",\n    \"InsurgencyEAC.exe\",\n    \"Launcher\", //Paradox Interactive Launcher\n    \"LeagueClient.exe\",\n    \"LeagueClientUxRender.exe\",\n    \"MarneLauncher.exe\",\n    \"MarvelRivals_Launcher.exe\",\n    \"monado-service\",\n    \"Origin.exe\",\n    \"OriginThinSetupInternal.exe\",\n    \"plutonium.exe\",\n    \"plutonium-launcher-win32.exe\",\n    \"REDlauncher.exe\",\n    \"REDprelauncher.exe\",\n    \"RSI Launcher.exe\",\n    \"rundll32.exe\",\n    \"SocialClubHelper.exe\",\n    \"StarCitizen_Launcher.exe\",\n    \"steam\",\n    \"Steam.exe\",\n    \"steamwebhelper\",\n    \"steamwebhelper.exe\",\n    \"tabtip.exe\",\n    \"UplayWebCore.exe\",\n    \"vrcompositor\",\n    \"vulkandriverquery\",\n};\n\nstatic std::vector<std::string> blacklist_engine {\n    \"GTK\"\n};\n\nstatic bool check_blacklisted() {\n    std::string proc_name = get_proc_name();\n    std::string engine_name = global_engine_name;\n    global_proc_name = proc_name;\n    bool blacklisted = std::find(blacklist.begin(), blacklist.end(), proc_name) != blacklist.end();\n    blacklisted |= std::find(blacklist_engine.begin(), blacklist_engine.end(), engine_name) != blacklist_engine.end();\n\n    static bool printed = false;\n    if(blacklisted && !printed) {\n        printed = true;\n        SPDLOG_INFO(\"process '{}' is blacklisted in MangoHud\", proc_name);\n    }\n\n    return blacklisted;\n}\n\nbool is_blacklisted(bool force_recheck) {\n    static bool blacklisted = check_blacklisted();\n    if (force_recheck)\n        blacklisted = check_blacklisted();\n    return blacklisted;\n}\n\nvoid add_blacklist(const std::string& new_item) {\n    // check if item exits in blacklist before adding new item\n    if(std::find(blacklist.begin(), blacklist.end(), new_item) != blacklist.end()) {\n        return;\n    }\n\n    blacklist.push_back (new_item);\n    is_blacklisted(true);\n}\n\n\n"
  },
  {
    "path": "src/blacklist.h",
    "content": "#pragma once\n#ifndef MANGOHUD_BLACKLIST_H\n#define MANGOHUD_BLACKLIST_H\n#include<string>\nbool is_blacklisted(bool force_recheck = false);\nvoid add_blacklist(const std::string& proc);\nextern std::string global_proc_name;\nextern std::string global_engine_name;\n\n#endif //MANGOHUD_BLACKLIST_H\n"
  },
  {
    "path": "src/config.cpp",
    "content": "#include <fstream>\n#include <sstream>\n#include <iostream>\n#include <string.h>\n#include <thread>\n#include <unordered_map>\n#include <string>\n#include <spdlog/spdlog.h>\n#include \"config.h\"\n#include \"file_utils.h\"\n#include \"string_utils.h\"\n#include \"hud_elements.h\"\n#include \"blacklist.h\"\n\nvoid parseConfigLine(std::string line, std::unordered_map<std::string, std::string>& options) {\n    std::string param, value;\n\n    if (line.find(\"#\") != std::string::npos)\n        line = line.erase(line.find(\"#\"), std::string::npos);\n\n    size_t equal = line.find(\"=\");\n    if (equal == std::string::npos)\n        value = \"1\";\n    else\n        value = line.substr(equal+1);\n\n    param = line.substr(0, equal);\n    trim(param);\n    trim(value);\n    if (!param.empty()){\n        HUDElements.options.push_back({param, value});\n        options[param] = value;\n    }\n}\n\nstatic std::string get_program_dir() {\n    const std::string exe_path = get_exe_path();\n    if (exe_path.empty()) {\n        return std::string();\n    }\n    const auto n = exe_path.find_last_of('/');\n    if (n != std::string::npos) {\n        return exe_path.substr(0, n);\n    }\n    return std::string();\n}\n\nstd::string get_program_name() {\n    const std::string exe_path = get_exe_path();\n    std::string basename = \"unknown\";\n    if (exe_path.empty()) {\n        return basename;\n    }\n    const auto n = exe_path.find_last_of('/');\n    if (n == std::string::npos) {\n        return basename;\n    }\n    if (n < exe_path.size() - 1) {\n        // An executable's name.\n        basename = exe_path.substr(n + 1);\n    }\n    return basename;\n}\n\nstatic void enumerate_config_files(std::vector<std::string>& paths) {\n    static const char *mangohud_dir = \"/MangoHud/\";\n\n    const std::string data_dir = get_data_dir();\n    const std::string config_dir = get_config_dir();\n\n    const std::string program_name = get_program_name();\n\n    if (config_dir.empty()) {\n        // If we can't find 'HOME' just abandon hope.\n        return;\n    }\n\n    paths.push_back(config_dir + mangohud_dir + \"MangoHud.conf\");\n    paths.push_back(\"/etc/MangoHud.conf\");\n\n    if (is_blacklisted()) {\n        // Don't bother looking for conf file\n        return;\n    }\n\n    if (!program_name.empty()) {\n        paths.push_back(config_dir + mangohud_dir + program_name + \".conf\");\n    }\n\n    const std::string program_dir = get_program_dir();\n    if (!program_dir.empty()) {\n        paths.push_back(program_dir + \"/MangoHud.conf\");\n    }\n\n    const std::string wine_program_name = get_wine_exe_name();\n    if (!wine_program_name.empty()) {\n        paths.push_back(config_dir + mangohud_dir + \"wine-\" + wine_program_name + \".conf\");\n     }\n}\n\nvoid parseConfigFile(overlay_params& params) {\n    std::vector<std::string> paths;\n    const char *cfg_file = getenv(\"MANGOHUD_CONFIGFILE\");\n\n    if (cfg_file)\n        paths.push_back(cfg_file);\n    else\n        enumerate_config_files(paths);\n#ifdef _WIN32\n    paths.push_back(\"C:\\\\mangohud\\\\MangoHud.conf\");\n#endif\n    std::string line;\n    for (auto p = paths.rbegin(); p != paths.rend(); p++) {\n        std::ifstream stream(*p);\n        if (!stream.good()) {\n            // printing just so user has an idea of possible configs\n            SPDLOG_DEBUG(\"skipping config: '{}' [ not found ]\", *p);\n            continue;\n        }\n\n        stream.imbue(std::locale::classic());\n        SPDLOG_DEBUG(\"parsing config: '{}'\", *p);\n        while (std::getline(stream, line))\n        {\n            parseConfigLine(line, params.options);\n        }\n        params.config_file_path = *p;\n        return;\n    }\n}\n"
  },
  {
    "path": "src/config.h",
    "content": "#pragma once\n#ifndef MANGOHUD_CONFIG_H\n#define MANGOHUD_CONFIG_H\n\n#include \"overlay_params.h\"\n#include <string>\n\nvoid parseConfigFile(overlay_params& p);\nstd::string get_program_name();\nvoid parseConfigLine(std::string line, std::unordered_map<std::string, std::string>& options);\n#endif //MANGOHUD_CONFIG_H\n"
  },
  {
    "path": "src/control.cpp",
    "content": "#include <cstdint>\n#include <assert.h>\n#include <cerrno>\n#include <cstring>\n#include <sys/socket.h>\n#include \"mesa/util/os_socket.h\"\n#include \"overlay.h\"\n#include \"version.h\"\n#include \"app/mangoapp.h\"\n\nint global_control_client;\n\nusing namespace std;\nstatic void parse_command(overlay_params &params,\n                          const char *cmd, unsigned cmdlen,\n                          const char *param, unsigned paramlen)\n{\n   if (!strncmp(cmd, \"hud\", cmdlen)) {\n      get_params()->no_display = !get_params()->no_display;\n   } else if (!strncmp(cmd, \"logging\", cmdlen)) {\n      if (param && param[0])\n      {\n         int value = atoi(param);\n         if (!value && logger->is_active())\n            logger->stop_logging();\n         else if (value > 0 && !logger->is_active())\n            logger->start_logging();\n      }\n      else\n      {\n         if (logger->is_active())\n            logger->stop_logging();\n         else\n            logger->start_logging();\n      }\n   } else if (!strncmp(cmd, \"fcat\", cmdlen)) {\n      params.enabled[OVERLAY_PARAM_ENABLED_fcat] = !params.enabled[OVERLAY_PARAM_ENABLED_fcat];\n   }\n}\n\n#define BUFSIZE 4096\n\n/**\n * This function will process commands through the control file.\n *\n * A command starts with a colon, followed by the command, and followed by an\n * option '=' and a parameter.  It has to end with a semi-colon. A full command\n * + parameter looks like:\n *\n *    :cmd=param;\n */\nstatic void process_char(const int control_client, overlay_params &params, char c)\n{\n   static char cmd[BUFSIZE];\n   static char param[BUFSIZE];\n\n   static unsigned cmdpos = 0;\n   static unsigned parampos = 0;\n   static bool reading_cmd = false;\n   static bool reading_param = false;\n\n   switch (c) {\n   case ':':\n      cmdpos = 0;\n      parampos = 0;\n      reading_cmd = true;\n      reading_param = false;\n      break;\n   case ';':\n      if (!reading_cmd)\n         break;\n      cmd[cmdpos++] = '\\0';\n      param[parampos++] = '\\0';\n      parse_command(params, cmd, cmdpos, param, parampos);\n      reading_cmd = false;\n      reading_param = false;\n      break;\n   case '=':\n      if (!reading_cmd)\n         break;\n      reading_param = true;\n      break;\n   default:\n      if (!reading_cmd)\n         break;\n\n      if (reading_param) {\n         /* overflow means an invalid parameter */\n         if (parampos >= BUFSIZE - 1) {\n            reading_cmd = false;\n            reading_param = false;\n            break;\n         }\n\n         param[parampos++] = c;\n      } else {\n         /* overflow means an invalid command */\n         if (cmdpos >= BUFSIZE - 1) {\n            reading_cmd = false;\n            break;\n         }\n\n         cmd[cmdpos++] = c;\n      }\n   }\n}\n\nvoid control_send(int control_client,\n                         const char *cmd, unsigned cmdlen,\n                         const char *param, unsigned paramlen)\n{\n   unsigned msglen = 0;\n   char buffer[BUFSIZE];\n\n   assert(cmdlen + paramlen + 3 < BUFSIZE);\n\n   buffer[msglen++] = ':';\n\n   memcpy(&buffer[msglen], cmd, cmdlen);\n   msglen += cmdlen;\n\n   if (paramlen > 0) {\n      buffer[msglen++] = '=';\n      memcpy(&buffer[msglen], param, paramlen);\n      msglen += paramlen;\n      buffer[msglen++] = ';';\n   }\n\n   os_socket_send(control_client, buffer, msglen, MSG_NOSIGNAL);\n}\n\nstatic void control_send_connection_string(int control_client, const std::string& deviceName)\n{\n   const char *controlVersionCmd = \"MangoHudControlVersion\";\n   const char *controlVersionString = \"1\";\n\n   control_send(control_client, controlVersionCmd, strlen(controlVersionCmd),\n                controlVersionString, strlen(controlVersionString));\n\n   const char *deviceCmd = \"DeviceName\";\n\n   control_send(control_client, deviceCmd, strlen(deviceCmd),\n                deviceName.c_str(), deviceName.size());\n\n   const char *versionCmd = \"MangoHudVersion\";\n   const char *versionString = \"MangoHud \" MANGOHUD_VERSION;\n\n   control_send(control_client, versionCmd, strlen(versionCmd),\n                versionString, strlen(versionString));\n\n}\n\nvoid control_client_check(int control, int& control_client, const std::string& deviceName)\n{\n   /* Already connected, just return. */\n   if (control_client >= 0){\n      global_control_client = control_client;\n      return;\n   }\n\n   int socket = os_socket_accept(control);\n   if (socket == -1) {\n      if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED)\n         fprintf(stderr, \"ERROR on socket: %s\\n\", strerror(errno));\n      return;\n   }\n\n   if (socket >= 0) {\n      os_socket_block(socket, false);\n      control_client = socket;\n      control_send_connection_string(control_client, deviceName);\n   }\n}\n\nstatic void control_client_disconnected(int& control_client)\n{\n   os_socket_close(control_client);\n   control_client = -1;\n}\n\nvoid process_control_socket(int& control_client, overlay_params &params)\n{\n   if (control_client >= 0) {\n      char buf[BUFSIZE];\n\n      while (true) {\n         ssize_t n = os_socket_recv(control_client, buf, BUFSIZE, 0);\n\n         if (n == -1) {\n            if (errno == EAGAIN || errno == EWOULDBLOCK) {\n               /* nothing to read, try again later */\n               break;\n            }\n\n            if (errno != ECONNRESET)\n               fprintf(stderr, \"ERROR on connection: %s\\n\", strerror(errno));\n\n            control_client_disconnected(control_client);\n         } else if (n == 0) {\n            /* recv() returns 0 when the client disconnects */\n            control_client_disconnected(control_client);\n         }\n\n         for (ssize_t i = 0; i < n; i++) {\n            process_char(control_client, params, buf[i]);\n         }\n\n         /* If we try to read BUFSIZE and receive BUFSIZE bytes from the\n          * socket, there's a good chance that there's still more data to be\n          * read, so we will try again. Otherwise, simply be done for this\n          * iteration and try again on the next frame.\n          */\n         if (n < BUFSIZE)\n            break;\n      }\n   }\n}\n"
  },
  {
    "path": "src/cpu.cpp",
    "content": "#include \"cpu.h\"\n#include <memory>\n#include <string>\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <dirent.h>\n#include <string.h>\n#include <algorithm>\n#include <regex>\n#include <inttypes.h>\n#include <spdlog/spdlog.h>\n#include \"string_utils.h\"\n#include \"gpu.h\"\n#include \"hud_elements.h\"\n\n#ifndef TEST_ONLY\n#include \"hud_elements.h\"\n#endif\n\n#ifndef PROCDIR\n#define PROCDIR \"/proc\"\n#endif\n\n#ifndef PROCSTATFILE\n#define PROCSTATFILE PROCDIR \"/stat\"\n#endif\n\n#ifndef PROCMEMINFOFILE\n#define PROCMEMINFOFILE PROCDIR \"/meminfo\"\n#endif\n\n#ifndef PROCCPUINFOFILE\n#define PROCCPUINFOFILE PROCDIR \"/cpuinfo\"\n#endif\n\n#include \"file_utils.h\"\n\nstatic void calculateCPUData(CPUData& cpuData,\n    unsigned long long int usertime,\n    unsigned long long int nicetime,\n    unsigned long long int systemtime,\n    unsigned long long int idletime,\n    unsigned long long int ioWait,\n    unsigned long long int irq,\n    unsigned long long int softIrq,\n    unsigned long long int steal,\n    unsigned long long int guest,\n    unsigned long long int guestnice)\n{\n    // Guest time is already accounted in usertime\n    usertime = usertime - guest;\n    nicetime = nicetime - guestnice;\n    // Fields existing on kernels >= 2.6\n    // (and RHEL's patched kernel 2.4...)\n    unsigned long long int idlealltime = idletime + ioWait;\n    unsigned long long int systemalltime = systemtime + irq + softIrq;\n    unsigned long long int virtalltime = guest + guestnice;\n    unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;\n\n    // Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()\n    // used in /proc/stat rounds down numbers, it can lead to a case where the\n    // integer overflow.\n    #define WRAP_SUBTRACT(a,b) (a > b) ? a - b : 0\n    cpuData.userPeriod = WRAP_SUBTRACT(usertime, cpuData.userTime);\n    cpuData.nicePeriod = WRAP_SUBTRACT(nicetime, cpuData.niceTime);\n    cpuData.systemPeriod = WRAP_SUBTRACT(systemtime, cpuData.systemTime);\n    cpuData.systemAllPeriod = WRAP_SUBTRACT(systemalltime, cpuData.systemAllTime);\n    cpuData.idleAllPeriod = WRAP_SUBTRACT(idlealltime, cpuData.idleAllTime);\n    cpuData.idlePeriod = WRAP_SUBTRACT(idletime, cpuData.idleTime);\n    cpuData.ioWaitPeriod = WRAP_SUBTRACT(ioWait, cpuData.ioWaitTime);\n    cpuData.irqPeriod = WRAP_SUBTRACT(irq, cpuData.irqTime);\n    cpuData.softIrqPeriod = WRAP_SUBTRACT(softIrq, cpuData.softIrqTime);\n    cpuData.stealPeriod = WRAP_SUBTRACT(steal, cpuData.stealTime);\n    cpuData.guestPeriod = WRAP_SUBTRACT(virtalltime, cpuData.guestTime);\n    cpuData.totalPeriod = WRAP_SUBTRACT(totaltime, cpuData.totalTime);\n    #undef WRAP_SUBTRACT\n    cpuData.userTime = usertime;\n    cpuData.niceTime = nicetime;\n    cpuData.systemTime = systemtime;\n    cpuData.systemAllTime = systemalltime;\n    cpuData.idleAllTime = idlealltime;\n    cpuData.idleTime = idletime;\n    cpuData.ioWaitTime = ioWait;\n    cpuData.irqTime = irq;\n    cpuData.softIrqTime = softIrq;\n    cpuData.stealTime = steal;\n    cpuData.guestTime = virtalltime;\n    cpuData.totalTime = totaltime;\n\n    if (cpuData.totalPeriod == 0)\n        return;\n    float total = (float)cpuData.totalPeriod;\n    float v[4];\n    v[0] = cpuData.nicePeriod * 100.0f / total;\n    v[1] = cpuData.userPeriod * 100.0f / total;\n\n    /* if not detailed */\n    v[2] = cpuData.systemAllPeriod * 100.0f / total;\n    v[3] = (cpuData.stealPeriod + cpuData.guestPeriod) * 100.0f / total;\n    //cpuData.percent = std::clamp(v[0]+v[1]+v[2]+v[3], 0.0f, 100.0f);\n    cpuData.percent = std::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f);\n}\n\nCPUStats::CPUStats()\n{\n}\n\nCPUStats::~CPUStats()\n{\n    if (m_cpuTempFile) {\n        fclose(m_cpuTempFile);\n        m_cpuTempFile = nullptr;\n    }\n}\n\nbool CPUStats::Init()\n{\n    if (m_inited)\n        return true;\n\n    std::string line;\n    std::ifstream file (PROCSTATFILE);\n    bool first = true;\n    m_cpuData.clear();\n\n    if (!file.is_open()) {\n        SPDLOG_ERROR(\"Failed to opening \" PROCSTATFILE);\n        return false;\n    }\n\n    do {\n        if (!std::getline(file, line)) {\n            SPDLOG_DEBUG(\"Failed to read all of \" PROCSTATFILE);\n            return false;\n        } else if (starts_with(line, \"cpu\")) {\n            if (first) {\n                first =false;\n                continue;\n            }\n\n            CPUData cpu = {};\n            cpu.totalTime = 1;\n            cpu.totalPeriod = 1;\n            sscanf(line.c_str(), \"cpu%4d \", &cpu.cpu_id);\n            m_cpuData.push_back(cpu);\n\n        } else if (starts_with(line, \"btime \")) {\n\n            // C++ way, kind of noisy\n            //std::istringstream token( line );\n            //std::string s;\n            //token >> s;\n            //token >> m_boottime;\n\n            // assume that if btime got read, that everything else is OK too\n            sscanf(line.c_str(), \"btime %lld\\n\", &m_boottime);\n            break;\n        }\n    } while(true);\n\n#ifndef TEST_ONLY\n    if (get_params()->enabled[OVERLAY_PARAM_ENABLED_core_type])\n        get_cpu_cores_types();\n#endif\n\n    m_inited = true;\n    return UpdateCPUData();\n}\n\nbool CPUStats::Reinit()\n{\n    m_inited = false;\n    return Init();\n}\n\n//TODO take sampling interval into account?\nbool CPUStats::UpdateCPUData()\n{\n    unsigned long long int usertime, nicetime, systemtime, idletime;\n    unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;\n    int cpuid = -1;\n    size_t cpu_count = 0;\n\n    if (!m_inited)\n        return false;\n\n    std::string line;\n    std::ifstream file (PROCSTATFILE);\n    bool ret = false;\n\n    if (!file.is_open()) {\n        SPDLOG_ERROR(\"Failed to opening \" PROCSTATFILE);\n        return false;\n    }\n\n    do {\n        if (!std::getline(file, line)) {\n            break;\n        } else if (!ret && sscanf(line.c_str(), \"cpu  %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu\",\n            &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 10) {\n            ret = true;\n            calculateCPUData(m_cpuDataTotal, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);\n        } else if (sscanf(line.c_str(), \"cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu\",\n            &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) {\n\n            //SPDLOG_DEBUG(\"Parsing 'cpu{}' line:{}\", cpuid, line);\n\n            if (!ret) {\n                SPDLOG_DEBUG(\"Failed to parse 'cpu' line:{}\", line);\n                return false;\n            }\n\n            if (cpuid < 0 /* can it? */) {\n                SPDLOG_DEBUG(\"Cpu id '{}' is out of bounds\", cpuid);\n                return false;\n            }\n\n            if (cpu_count + 1 > m_cpuData.size() || m_cpuData[cpu_count].cpu_id != cpuid) {\n                SPDLOG_DEBUG(\"Cpu id '{}' is out of bounds or wrong index, reiniting\", cpuid);\n                return Reinit();\n            }\n\n            CPUData& cpuData = m_cpuData[cpu_count];\n            calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);\n            cpuid = -1;\n            cpu_count++;\n\n        } else {\n            break;\n        }\n    } while(true);\n\n    if (cpu_count < m_cpuData.size())\n        m_cpuData.resize(cpu_count);\n\n    m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();\n    m_updatedCPUs = true;\n    return ret;\n}\n\nbool CPUStats::UpdateCoreMhz() {\n    m_coreMhz.clear();\n    FILE *fp;\n    static bool scaling_freq = true;\n    if (scaling_freq){\n        for (auto& cpu : m_cpuData){\n            std::string path = \"/sys/devices/system/cpu/cpu\" + std::to_string(cpu.cpu_id) + \"/cpufreq/scaling_cur_freq\";\n            if ((fp = fopen(path.c_str(), \"r\"))){\n                int64_t temp;\n                if (fscanf(fp, \"%\" PRId64, &temp) != 1)\n                    temp = 0;\n                cpu.mhz = temp / 1000;\n                fclose(fp);\n                scaling_freq = true;\n            } else {\n                scaling_freq = false;\n                break;\n            }\n        }\n    } else {\n        static std::ifstream cpuInfo(PROCCPUINFOFILE);\n        static std::string row;\n        size_t i = 0;\n        while (std::getline(cpuInfo, row) && i < m_cpuData.size()) {\n            if (row.find(\"MHz\") != std::string::npos){\n                row = std::regex_replace(row, std::regex(R\"([^0-9.])\"), \"\");\n                if (!try_stoi(m_cpuData[i].mhz, row))\n                    m_cpuData[i].mhz = 0;\n                i++;\n            }\n        }\n    }\n\n    m_cpuDataTotal.cpu_mhz = 0;\n    for (auto data : m_cpuData)\n        if (data.mhz > m_cpuDataTotal.cpu_mhz)\n            m_cpuDataTotal.cpu_mhz = data.mhz;\n\n    return true;\n}\n\nbool CPUStats::ReadcpuTempFile(int& temp) {\n\tif (!m_cpuTempFile)\n\t\treturn false;\n\n\trewind(m_cpuTempFile);\n\tfflush(m_cpuTempFile);\n\tbool ret = (fscanf(m_cpuTempFile, \"%d\", &temp) == 1);\n\ttemp = temp / 1000;\n\n\treturn ret;\n}\n\nbool CPUStats::UpdateCpuTemp() {\n    if (gpus) {\n        for (auto gpu : gpus->available_gpus) {\n            if (gpu->is_apu()) {\n                m_cpuDataTotal.temp = gpu->metrics.apu_cpu_temp;\n                return true;\n            }\n        }\n    }\n\n    int temp = 0;\n    bool ret = ReadcpuTempFile(temp);\n    m_cpuDataTotal.temp = temp;\n\n    return ret;\n}\n\nstatic bool get_cpu_power_k10temp(CPUPowerData* cpuPowerData, float& power) {\n    CPUPowerData_k10temp* powerData_k10temp = (CPUPowerData_k10temp*)cpuPowerData;\n\n    if(powerData_k10temp->corePowerFile || powerData_k10temp->socPowerFile)\n    {\n        rewind(powerData_k10temp->corePowerFile);\n        rewind(powerData_k10temp->socPowerFile);\n        fflush(powerData_k10temp->corePowerFile);\n        fflush(powerData_k10temp->socPowerFile);\n        int corePower, socPower;\n        if (fscanf(powerData_k10temp->corePowerFile, \"%d\", &corePower) != 1)\n            goto voltagebased;\n        if (fscanf(powerData_k10temp->socPowerFile, \"%d\", &socPower) != 1)\n            goto voltagebased;\n        power = (corePower + socPower) / 1000000;\n        return true;\n    }\n    voltagebased:\n    if (!powerData_k10temp->coreVoltageFile || !powerData_k10temp->coreCurrentFile || !powerData_k10temp->socVoltageFile || !powerData_k10temp->socCurrentFile)\n        return false;\n    rewind(powerData_k10temp->coreVoltageFile);\n    rewind(powerData_k10temp->coreCurrentFile);\n    rewind(powerData_k10temp->socVoltageFile);\n    rewind(powerData_k10temp->socCurrentFile);\n\n    fflush(powerData_k10temp->coreVoltageFile);\n    fflush(powerData_k10temp->coreCurrentFile);\n    fflush(powerData_k10temp->socVoltageFile);\n    fflush(powerData_k10temp->socCurrentFile);\n\n    int coreVoltage, coreCurrent;\n    int socVoltage, socCurrent;\n\n    if (fscanf(powerData_k10temp->coreVoltageFile, \"%d\", &coreVoltage) != 1)\n        return false;\n    if (fscanf(powerData_k10temp->coreCurrentFile, \"%d\", &coreCurrent) != 1)\n        return false;\n    if (fscanf(powerData_k10temp->socVoltageFile, \"%d\", &socVoltage) != 1)\n        return false;\n    if (fscanf(powerData_k10temp->socCurrentFile, \"%d\", &socCurrent) != 1)\n        return false;\n\n    power = (coreVoltage * coreCurrent + socVoltage * socCurrent) / 1000000;\n\n    return true;\n}\n\nstatic bool get_cpu_power_zenpower(CPUPowerData* cpuPowerData, float& power) {\n    CPUPowerData_zenpower* powerData_zenpower = (CPUPowerData_zenpower*)cpuPowerData;\n\n    if (!powerData_zenpower->corePowerFile || !powerData_zenpower->socPowerFile)\n        return false;\n\n    rewind(powerData_zenpower->corePowerFile);\n    rewind(powerData_zenpower->socPowerFile);\n\n    fflush(powerData_zenpower->corePowerFile);\n    fflush(powerData_zenpower->socPowerFile);\n\n    int corePower, socPower;\n\n    if (fscanf(powerData_zenpower->corePowerFile, \"%d\", &corePower) != 1)\n        return false;\n    if (fscanf(powerData_zenpower->socPowerFile, \"%d\", &socPower) != 1)\n        return false;\n\n    power = (corePower + socPower) / 1000000;\n\n    return true;\n}\n\nstatic bool get_cpu_power_zenergy(CPUPowerData* cpuPowerData, float& power) {\n    CPUPowerData_zenergy* powerData_zenergy = (CPUPowerData_zenergy*)cpuPowerData;\n    if (!powerData_zenergy->energyCounterFile)\n        return false;\n\n    rewind(powerData_zenergy->energyCounterFile);\n    fflush(powerData_zenergy->energyCounterFile);\n\n    uint64_t energyCounterValue = 0;\n    if (fscanf(powerData_zenergy->energyCounterFile, \"%\" SCNu64, &energyCounterValue) != 1)\n        return false;\n\n    Clock::time_point now = Clock::now();\n    Clock::duration timeDiff = now - powerData_zenergy->lastCounterValueTime;\n    int64_t timeDiffMicro = std::chrono::duration_cast<std::chrono::microseconds>(timeDiff).count();\n    uint64_t energyCounterDiff = energyCounterValue - powerData_zenergy->lastCounterValue;\n\n\n    if (powerData_zenergy->lastCounterValue > 0 && energyCounterValue > powerData_zenergy->lastCounterValue)\n        power = (float) energyCounterDiff / (float) timeDiffMicro;\n\n    powerData_zenergy->lastCounterValue = energyCounterValue;\n    powerData_zenergy->lastCounterValueTime = now;\n\n    return true;\n}\n\nstatic bool get_cpu_power_rapl(CPUPowerData* cpuPowerData, float& power) {\n    CPUPowerData_rapl* powerData_rapl = (CPUPowerData_rapl*)cpuPowerData;\n\n    if (!powerData_rapl->energyCounterFile)\n        return false;\n\n    rewind(powerData_rapl->energyCounterFile);\n    fflush(powerData_rapl->energyCounterFile);\n\n    uint64_t energyCounterValue = 0;\n    if (fscanf(powerData_rapl->energyCounterFile, \"%\" SCNu64, &energyCounterValue) != 1)\n        return false;\n\n    Clock::time_point now = Clock::now();\n    Clock::duration timeDiff = now - powerData_rapl->lastCounterValueTime;\n    int64_t timeDiffMicro = std::chrono::duration_cast<std::chrono::microseconds>(timeDiff).count();\n    uint64_t energyCounterDiff = energyCounterValue - powerData_rapl->lastCounterValue;\n\n    if (powerData_rapl->lastCounterValue > 0 && energyCounterValue > powerData_rapl->lastCounterValue)\n        power = energyCounterDiff / timeDiffMicro;\n\n    powerData_rapl->lastCounterValue = energyCounterValue;\n    powerData_rapl->lastCounterValueTime = now;\n\n    return true;\n}\n\nstatic bool get_cpu_power_amdgpu(float& power) {\n    if (gpus)\n        for (auto gpu : gpus->available_gpus)\n            if (gpu->is_apu()) {\n                power = gpu->metrics.apu_cpu_power;\n                return true;\n            }\n\n    return false;\n}\n\nstatic bool get_cpu_power_xgene(CPUPowerData* cpuPowerData, float& power) {\n    CPUPowerData_xgene* powerData_xgene = (CPUPowerData_xgene*)cpuPowerData;\n    if (!powerData_xgene->powerFile)\n        return false;\n\n    rewind(powerData_xgene->powerFile);\n    fflush(powerData_xgene->powerFile);\n\n    uint64_t powerValue = 0;\n    if (fscanf(powerData_xgene->powerFile, \"%\" SCNu64, &powerValue) != 1)\n        return false;\n\n    power = (float) powerValue / 1000000.0f;\n\n    return true;\n}\n\nbool CPUStats::UpdateCpuPower() {\n    InitCpuPowerData();\n\n    if(!m_cpuPowerData)\n        return false;\n\n    float power = 0;\n\n    switch(m_cpuPowerData->source) {\n        case CPU_POWER_K10TEMP:\n            if (!get_cpu_power_k10temp(m_cpuPowerData.get(), power)) return false;\n            break;\n        case CPU_POWER_ZENPOWER:\n            if (!get_cpu_power_zenpower(m_cpuPowerData.get(), power)) return false;\n            break;\n        case CPU_POWER_ZENERGY:\n            if (!get_cpu_power_zenergy(m_cpuPowerData.get(), power)) return false;\n            break;\n        case CPU_POWER_RAPL:\n            if (!get_cpu_power_rapl(m_cpuPowerData.get(), power)) return false;\n            break;\n        case CPU_POWER_AMDGPU:\n            if (!get_cpu_power_amdgpu(power)) return false;\n            break;\n        case CPU_POWER_XGENE:\n            if (!get_cpu_power_xgene(m_cpuPowerData.get(), power)) return false;\n            break;\n        default:\n            return false;\n    }\n\n    m_cpuDataTotal.power = power;\n\n    return true;\n}\n\nstatic bool find_input(const std::string& path, const char* input_prefix, std::string& input, const std::string& name)\n{\n    auto files = ls(path.c_str(), input_prefix, LS_FILES);\n    for (auto& file : files) {\n        if (!ends_with(file, \"_label\"))\n            continue;\n\n        auto label = read_line(path + \"/\" + file);\n        if (label != name)\n            continue;\n\n        auto uscore = file.find_first_of(\"_\");\n        if (uscore != std::string::npos) {\n            file.erase(uscore, std::string::npos);\n            input = path + \"/\" + file + \"_input\";\n            //9 characters should not overflow the 32-bit int\n            return std::stoi(read_line(input).substr(0, 9)) > 0;\n        }\n    }\n    return false;\n}\n\nstatic bool find_fallback_input(const std::string& path, const char* input_prefix, std::string& input)\n{\n    auto files = ls(path.c_str(), input_prefix, LS_FILES);\n    if (!files.size())\n        return false;\n\n    std::sort(files.begin(), files.end());\n    for (auto& file : files) {\n        if (!ends_with(file, \"_input\"))\n            continue;\n        input = path + \"/\" + file;\n\t\tSPDLOG_DEBUG(\"fallback cpu {} input: {}\", input_prefix, input);\n        return true;\n    }\n    return false;\n}\n\nstatic void check_thermal_zones(std::string& path, std::string& input) {\n    std::string sysfs_thermal = \"/sys/class/thermal/\";\n\n    if (!fs::exists(sysfs_thermal))\n        return;\n\n    for (auto& d : fs::directory_iterator(sysfs_thermal)) {\n        if (d.path().filename().string().substr(0, 12) != \"thermal_zone\")\n            continue;\n\n        std::string type = read_line(d / \"type\");\n        if (type.substr(0, 6) != \"cpuss-\")\n            continue;\n\n        path = d.path();\n        input = d / \"temp\";\n\n        return;\n    }\n}\n\nbool CPUStats::GetCpuFile() {\n    if (m_cpuTempFile)\n        return true;\n\n    std::string name, path, input;\n    std::string hwmon = \"/sys/class/hwmon/\";\n    std::smatch match;\n\n    auto dirs = ls(hwmon.c_str());\n    for (auto& dir : dirs) {\n        path = hwmon + dir;\n        name = read_line(path + \"/name\");\n        SPDLOG_DEBUG(\"hwmon: sensor name: {}\", name);\n\n        std::map<std::string, std::string> custom_sensor = get_params()->cpu_custom_temp_sensor;\n\n        if (!custom_sensor[\"hwmon_name\"].empty() && !custom_sensor[\"hwmon_input\"].empty()) {\n            if (name != custom_sensor[\"hwmon_name\"])\n                continue;\n\n            find_fallback_input(path, custom_sensor[\"hwmon_input\"].c_str(), input);\n            break;\n        } else if (name == \"coretemp\") {\n            find_input(path, \"temp\", input, \"Package id 0\");\n            break;\n        } else if ((name == \"zenpower\" || name == \"k10temp\")) {\n            if (!find_input(path, \"temp\", input, \"Tdie\"))\n                find_input(path, \"temp\", input, \"Tctl\");\n            break;\n        } else if (name == \"atk0110\") {\n            find_input(path, \"temp\", input, \"CPU Temperature\");\n            break;\n        } else if (name == \"it8603\") {\n            find_input(path, \"temp\", input, \"temp1\");\n            break;\n        } else if (starts_with(name, \"cpuss0_\")) {\n            find_fallback_input(path, \"temp1\", input);\n            break;\n        } else if (starts_with(name, \"nct\")) {\n            // Only break if nct module has TSI0_TEMP node\n            if (find_input(path, \"temp\", input, \"TSI0_TEMP\"))\n                break;\n\n        } else if (name == \"asusec\") {\n            // Only break if module has CPU node\n            if (find_input(path, \"temp\", input, \"CPU\"))\n                break;\n        } else if (name == \"l_pcs\") {\n            // E2K (Elbrus 2000) CPU temperature module\n            find_input(path, \"temp\", input, \"Node 0 Max\");\n            break;\n        } else if (std::regex_match(name, match, std::regex(\"cpu\\\\d*_thermal\"))) {\n            find_fallback_input(path, \"temp1\", input);\n            break;\n        } else if (name == \"apm_xgene\") {\n            find_input(path, \"temp\", input, \"SoC Temperature\");\n            break;\n        } else {\n            path.clear();\n        }\n    }\n\n    if (path.empty()) {\n        try {\n            check_thermal_zones(path, input);\n        } catch (fs::filesystem_error& ex) {\n            SPDLOG_DEBUG(\"check_thermal_zones: {}\", ex.what());\n        }\n    }\n\n    if (input.empty() || !file_exists(input)) {\n        SPDLOG_ERROR(\"Could not find cpu temp sensor location\");\n        return false;\n    }\n\n    SPDLOG_INFO(\"hwmon: using input: {}\", input);\n    m_cpuTempFile = fopen(input.c_str(), \"r\");\n\n    return true;\n}\n\nstatic CPUPowerData_k10temp* init_cpu_power_data_k10temp(const std::string path) {\n    auto powerData = std::make_unique<CPUPowerData_k10temp>();\n\n    std::string coreVoltageInput, coreCurrentInput;\n    std::string socVoltageInput, socCurrentInput;\n    std::string socPowerInput, corePowerInput;\n\n    if(find_input(path, \"power\", corePowerInput, \"Pcore\") && find_input(path, \"power\", socPowerInput, \"Psoc\")) {\n        powerData->corePowerFile = fopen(corePowerInput.c_str(), \"r\");\n        powerData->socPowerFile = fopen(socPowerInput.c_str(), \"r\");\n        SPDLOG_DEBUG(\"hwmon: using input: {}\", corePowerInput);\n        SPDLOG_DEBUG(\"hwmon: using input: {}\", socPowerInput);\n        return powerData.release();\n    }\n\n    if(!find_input(path, \"in\", coreVoltageInput, \"Vcore\")) return nullptr;\n    if(!find_input(path, \"curr\", coreCurrentInput, \"Icore\")) return nullptr;\n    if(!find_input(path, \"in\", socVoltageInput, \"Vsoc\")) return nullptr;\n    if(!find_input(path, \"curr\", socCurrentInput, \"Isoc\")) return nullptr;\n\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", coreVoltageInput);\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", coreCurrentInput);\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", socVoltageInput);\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", socCurrentInput);\n\n    powerData->coreVoltageFile = fopen(coreVoltageInput.c_str(), \"r\");\n    powerData->coreCurrentFile = fopen(coreCurrentInput.c_str(), \"r\");\n    powerData->socVoltageFile = fopen(socVoltageInput.c_str(), \"r\");\n    powerData->socCurrentFile = fopen(socCurrentInput.c_str(), \"r\");\n\n    return powerData.release();\n}\n\nstatic CPUPowerData_zenpower* init_cpu_power_data_zenpower(const std::string path) {\n    auto powerData = std::make_unique<CPUPowerData_zenpower>();\n\n    std::string corePowerInput, socPowerInput;\n\n    if(!find_input(path, \"power\", corePowerInput, \"SVI2_P_Core\")) return nullptr;\n    if(!find_input(path, \"power\", socPowerInput, \"SVI2_P_SoC\")) return nullptr;\n\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", corePowerInput);\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", socPowerInput);\n\n    powerData->corePowerFile = fopen(corePowerInput.c_str(), \"r\");\n    powerData->socPowerFile = fopen(socPowerInput.c_str(), \"r\");\n\n    return powerData.release();\n}\n\nstatic CPUPowerData_zenergy* init_cpu_power_data_zenergy(const std::string path) {\n    auto powerData = std::make_unique<CPUPowerData_zenergy>();\n    std::string energyCounterPath;\n\n    if(!find_input(path, \"energy\", energyCounterPath, \"Esocket0\")) return nullptr;\n\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", energyCounterPath);\n    powerData->energyCounterFile = fopen(energyCounterPath.c_str(), \"r\");\n\n    return powerData.release();\n}\n\nstatic CPUPowerData_rapl* init_cpu_power_data_rapl(const std::string path) {\n    auto powerData = std::make_unique<CPUPowerData_rapl>();\n\n    std::string energyCounterPath = path + \"/energy_uj\";\n    if (!file_exists(energyCounterPath)) return nullptr;\n\n    powerData->energyCounterFile = fopen(energyCounterPath.c_str(), \"r\");\n    if (!powerData->energyCounterFile) {\n        SPDLOG_DEBUG(\"Rapl: energy_uj is not accessible\");\n        powerData->energyCounterFile = nullptr;\n        return nullptr;\n    }\n\n    return powerData.release();\n}\n\nstatic CPUPowerData_xgene* init_cpu_power_data_xgene(const std::string path) {\n    auto powerData = std::make_unique<CPUPowerData_xgene>();\n    std::string powerPath;\n\n    if(!find_input(path, \"power\", powerPath, \"CPU power\")) return nullptr;\n\n    SPDLOG_DEBUG(\"hwmon: using input: {}\", powerPath);\n    powerData->powerFile = fopen(powerPath.c_str(), \"r\");\n\n    return powerData.release();\n}\n\nbool CPUStats::InitCpuPowerData() {\n    if(m_cpuPowerData != nullptr)\n        return true;\n\n    // only try to find a valid method 5 times\n    static int retries = 0;\n    if (retries >= 5)\n        return true;\n\n    retries++;\n    \n    std::string name, path;\n    std::string hwmon = \"/sys/class/hwmon/\";\n\n    CPUPowerData* cpuPowerData = nullptr;\n\n    auto dirs = ls(hwmon.c_str());\n    for (auto& dir : dirs) {\n        path = hwmon + dir;\n        name = read_line(path + \"/name\");\n        SPDLOG_DEBUG(\"hwmon: sensor name: {}\", name);\n\n        if (name == \"k10temp\") {\n            cpuPowerData = (CPUPowerData*)init_cpu_power_data_k10temp(path);\n        } else if (name == \"zenpower\") {\n            cpuPowerData = (CPUPowerData*)init_cpu_power_data_zenpower(path);\n            break;\n        } else if (name == \"zenergy\") {\n            cpuPowerData = (CPUPowerData*)init_cpu_power_data_zenergy(path);\n            break;\n        } else if (name == \"apm_xgene\") {\n            cpuPowerData = (CPUPowerData*)init_cpu_power_data_xgene(path);\n            break;\n        }\n    }\n\n    if (!cpuPowerData) {\n        if (gpus) {\n            for (auto gpu : gpus->available_gpus) {\n                if (gpu->vendor_id == 0x1002 && gpu->is_apu() && gpu->get_metrics().apu_cpu_power > 0) {\n                    auto powerData = std::make_unique<CPUPowerData_amdgpu>();\n                    cpuPowerData = (CPUPowerData*)powerData.release();\n                }\n            }\n        }\n    }\n\n    if (!cpuPowerData) {\n        std::string powercap = \"/sys/class/powercap/\";\n        auto powercap_dirs = ls(powercap.c_str());\n        for (auto& dir : powercap_dirs) {\n            path = powercap + dir;\n            name = read_line(path + \"/name\");\n            SPDLOG_DEBUG(\"powercap: name: {}\", name);\n            if (name == \"package-0\") {\n                cpuPowerData = (CPUPowerData*)init_cpu_power_data_rapl(path);\n                break;\n            }\n        }\n    }\n    \n    if(cpuPowerData == nullptr) {\n        SPDLOG_ERROR(\"Failed to initialize CPU power data\");\n        return false;\n    }\n\n    m_cpuPowerData.reset(cpuPowerData);\n    return true;\n}\n\nvoid CPUStats::get_cpu_cores_types() {\n#if defined(__x86_64__) || defined(__i386__)\n    std::ifstream cpuinfo(PROCCPUINFOFILE);\n\n    if (!cpuinfo.is_open()) {\n        SPDLOG_ERROR(\"failed to open {}\", PROCCPUINFOFILE);\n        return;\n    }\n\n    std::string vendor = \"unknown\";\n    for (std::string line; std::getline(cpuinfo, line);) {\n        if (line.empty() || line.find(\":\") + 1 == line.length())\n            continue;\n\n        std::string key = line.substr(0, line.find(\":\") - 1);\n        std::string val = line.substr(key.length() + 3);\n\n        if (key == \"vendor_id\") {\n            vendor = val;\n            break;\n        }\n    }\n\n    SPDLOG_INFO(\"cpu vendor: {}\", vendor);\n\n    if (vendor == \"GenuineIntel\")\n        get_cpu_cores_types_intel();\n#endif\n\n#if defined(__arm__) || defined(__aarch64__)\n    get_cpu_cores_types_arm();\n#endif\n}\n\nvoid CPUStats::get_cpu_cores_types_intel() {\n    for (auto const& it : intel_cores) {\n        auto key = it.first;\n        auto file = it.second;\n\n        std::ifstream core_file(file);\n\n        if (!core_file.is_open()) {\n            SPDLOG_ERROR(\"failed to open core info file\");\n            return;\n        }\n\n        std::string cpus;\n        std::getline(core_file, cpus);\n\n        std::regex rx(\"(\\\\d+)-(\\\\d+)\");\n        std::smatch matches;\n\n        if (!std::regex_match(cpus, matches, rx) || matches.size() != 3)\n            continue;\n\n        int start = 0, end = 0;\n\n        try {\n            start = std::stoi(matches[1]);\n            end = std::stoi(matches[2]) + 1;\n        } catch (...) {\n            SPDLOG_ERROR(\"error parsing cpus \\\"{}\\\"\", cpus);\n        }\n\n        for (int i = start; i < end; i++) {\n            for (size_t k = 0; k < m_cpuData.size(); k++) {\n                if (m_cpuData[k].cpu_id != i)\n                    continue;\n\n                m_cpuData[k].label = key;\n                break;\n            }\n        }\n    }\n}\n\nvoid CPUStats::get_cpu_cores_types_arm() {\n    std::ifstream cpuinfo(PROCCPUINFOFILE);\n\n    if (!cpuinfo.is_open()) {\n        SPDLOG_ERROR(\"failed to open {}\", PROCCPUINFOFILE);\n        return;\n    }\n\n    uint8_t cur_core = 0;\n    bool detected_first_core = false;\n\n    for (std::string line; std::getline(cpuinfo, line);) {\n        if (line.empty() || line.find(\":\") + 1 == line.length())\n            continue;\n\n        auto key = line.substr(0, line.find(\":\") - 1);\n        auto val = line.substr(key.length() + 3);\n\n        if (key != \"CPU part\")\n            continue;\n\n        if (detected_first_core)\n            cur_core += 1;\n        else\n            detected_first_core = true;\n\n        std::string core_type;\n\n        try {\n            core_type = arm_cores.at(val);\n            SPDLOG_INFO(\"found {} core\", core_type);\n        }\n        catch(const std::out_of_range& ex) {\n            SPDLOG_WARN(\"unknown cpu part {}\", val);\n            continue;\n        }\n\n        // just in case\n        for (size_t i = 0; i < m_cpuData.size(); i++) {\n            if (m_cpuData[i].cpu_id != cur_core)\n                continue;\n\n            m_cpuData[i].label = core_type;\n        }\n    }\n}\n\nCPUStats cpuStats;\n"
  },
  {
    "path": "src/cpu.h",
    "content": "#pragma once\n#ifndef MANGOHUD_CPU_H\n#define MANGOHUD_CPU_H\n\n#include <vector>\n#include <cstdint>\n#include <cstdio>\n#include <memory>\n#include <string>\n#ifdef WIN32\n#include <windows.h>\n#endif\n#include \"timing.hpp\"\n#include \"gpu.h\"\n\ntypedef struct CPUData_ {\n   unsigned long long int totalTime;\n   unsigned long long int userTime;\n   unsigned long long int systemTime;\n   unsigned long long int systemAllTime;\n   unsigned long long int idleAllTime;\n   unsigned long long int idleTime;\n   unsigned long long int niceTime;\n   unsigned long long int ioWaitTime;\n   unsigned long long int irqTime;\n   unsigned long long int softIrqTime;\n   unsigned long long int stealTime;\n   unsigned long long int guestTime;\n\n   unsigned long long int totalPeriod;\n   unsigned long long int userPeriod;\n   unsigned long long int systemPeriod;\n   unsigned long long int systemAllPeriod;\n   unsigned long long int idleAllPeriod;\n   unsigned long long int idlePeriod;\n   unsigned long long int nicePeriod;\n   unsigned long long int ioWaitPeriod;\n   unsigned long long int irqPeriod;\n   unsigned long long int softIrqPeriod;\n   unsigned long long int stealPeriod;\n   unsigned long long int guestPeriod;\n\n   int cpu_id;\n   float percent;\n   int mhz;\n   int temp;\n   int cpu_mhz;\n   float power;\n\n   std::string label = \"unknown\";\n} CPUData;\n\nenum {\n   CPU_POWER_K10TEMP,\n   CPU_POWER_ZENPOWER,\n   CPU_POWER_ZENERGY,\n   CPU_POWER_RAPL,\n   CPU_POWER_AMDGPU,\n   CPU_POWER_XGENE\n};\n\nstruct CPUPowerData {\n   virtual ~CPUPowerData() = default;\n   int source;\n};\n\nstruct CPUPowerData_k10temp : public CPUPowerData {\n   CPUPowerData_k10temp() {\n      this->source = CPU_POWER_K10TEMP;\n   };\n\n   ~CPUPowerData_k10temp() {\n      if(this->coreVoltageFile)\n         fclose(this->coreVoltageFile);\n      if(this->coreCurrentFile)\n         fclose(this->coreCurrentFile);\n      if(this->socVoltageFile)\n         fclose(this->socVoltageFile);\n      if(this->socCurrentFile)\n         fclose(this->socCurrentFile);\n      if(this->corePowerFile)\n         fclose(this->corePowerFile);\n      if(this->socPowerFile)\n         fclose(this->socPowerFile);\n   };\n\n   FILE* coreVoltageFile {nullptr};\n   FILE* coreCurrentFile {nullptr};\n   FILE* socVoltageFile {nullptr};\n   FILE* socCurrentFile {nullptr};\n   FILE* corePowerFile {nullptr};\n   FILE* socPowerFile {nullptr};\n};\n\nstruct CPUPowerData_zenpower : public CPUPowerData {\n   CPUPowerData_zenpower() {\n      this->source = CPU_POWER_ZENPOWER;\n   };\n\n   ~CPUPowerData_zenpower() {\n      if(this->corePowerFile)\n         fclose(this->corePowerFile);\n      if(this->socPowerFile)\n         fclose(this->socPowerFile);\n   };\n\n   FILE* corePowerFile {nullptr};\n   FILE* socPowerFile {nullptr};\n};\n\nstruct CPUPowerData_zenergy : public CPUPowerData {\n   CPUPowerData_zenergy() {\n      this->source = CPU_POWER_ZENERGY;\n      this->lastCounterValue = 0;\n      this->lastCounterValueTime = Clock::now();\n   };\n\n   ~CPUPowerData_zenergy() {\n      if(this->energyCounterFile)\n         fclose(this->energyCounterFile);\n   };\n\n   FILE* energyCounterFile {nullptr};\n   uint64_t lastCounterValue;\n   Clock::time_point lastCounterValueTime;\n};\n\nstruct CPUPowerData_rapl : public CPUPowerData {\n   CPUPowerData_rapl() {\n      this->source = CPU_POWER_RAPL;\n      this->lastCounterValue = 0;\n      this->lastCounterValueTime = Clock::now();\n   };\n\n   ~CPUPowerData_rapl() {\n      if(this->energyCounterFile)\n         fclose(this->energyCounterFile);\n   };\n\n   FILE* energyCounterFile {nullptr};\n   uint64_t lastCounterValue;\n   Clock::time_point lastCounterValueTime;\n};\n\nstruct CPUPowerData_amdgpu : public CPUPowerData {\n   CPUPowerData_amdgpu() {\n      this->source = CPU_POWER_AMDGPU;\n   };\n};\n\n\nstruct CPUPowerData_xgene : public CPUPowerData {\n   CPUPowerData_xgene() {\n      this->source = CPU_POWER_XGENE;\n   };\n\n   ~CPUPowerData_xgene() {\n      if(this->powerFile)\n         fclose(this->powerFile);\n   };\n\n   FILE* powerFile {nullptr};\n};\n\nclass CPUStats\n{\npublic:\n   CPUStats();\n   ~CPUStats();\n   bool Init();\n   bool Reinit();\n   bool Updated()\n   {\n      return m_updatedCPUs;\n   }\n\n   bool UpdateCPUData();\n   bool UpdateCoreMhz();\n   bool UpdateCpuTemp();\n   bool UpdateCpuPower();\n   bool ReadcpuTempFile(int& temp);\n   bool GetCpuFile();\n   bool InitCpuPowerData();\n   double GetCPUPeriod() { return m_cpuPeriod; }\n   void get_cpu_cores_types();\n   void get_cpu_cores_types_intel();\n   void get_cpu_cores_types_arm();\n\n   const std::vector<CPUData>& GetCPUData() const {\n      return m_cpuData;\n   }\n   const CPUData& GetCPUDataTotal() const {\n      return m_cpuDataTotal;\n   }\nprivate:\n   unsigned long long int m_boottime = 0;\n   std::vector<CPUData> m_cpuData;\n   CPUData m_cpuDataTotal {};\n   std::vector<int> m_coreMhz;\n   double m_cpuPeriod = 0;\n   bool m_updatedCPUs = false; // TODO use caching or just update?\n   bool m_inited = false;\n   FILE *m_cpuTempFile = nullptr;\n   std::unique_ptr<CPUPowerData> m_cpuPowerData;\n\n   const std::map<std::string, std::string> intel_cores = {\n      {\"P\", \"/sys/devices/cpu_core/cpus\"},\n      {\"E\", \"/sys/devices/cpu_atom/cpus\"}\n   };\n\n   const std::map<std::string, std::string> arm_cores = {\n      // Performance cores\n      {\"0xd07\", \"A57\"},\n      {\"0xd08\", \"A72\"},\n      {\"0xd09\", \"A73\"},\n      {\"0xd0a\", \"A75\"},\n      {\"0xd0b\", \"A76\"},\n      {\"0xd0c\", \"A77\"},\n      {\"0xd41\", \"A78\"},\n      {\"0xd44\", \"X1\"},\n      {\"0xd4d\", \"X2\"},\n      {\"0xd4e\", \"X3\"},\n      {\"0xd47\", \"A710\"},\n      {\"0xd4f\", \"A720\"},\n      {\"0xd4b\", \"X4\"},\n\n      // Efficiency Cores\n      {\"0xd03\", \"A53\"},\n      {\"0xd05\", \"A55\"},\n      {\"0xd46\", \"A510\"},\n      {\"0xd4a\", \"A520\"},\n\n      // General-Purpose Cores\n      {\"0xd04\", \"A35\"},\n      {\"0xd06\", \"A65\"}\n   };\n};\n\nextern CPUStats cpuStats;\n#ifdef WIN32\nuint64_t FileTimeToInt64( const FILETIME& ft );\n#endif\n#endif //MANGOHUD_CPU_H\n"
  },
  {
    "path": "src/cpu_win32.cpp",
    "content": "#include <windows.h>\n#include <thread>\n#include <string.h>\n#include \"cpu.h\"\n#include <iostream>\n#define SystemProcessorPerformanceInformation 0x8\n#define SystemBasicInformation    0x0\nFILETIME last_userTime, last_kernelTime, last_idleTime;\n\nuint64_t FileTimeToInt64( const FILETIME& ft ) {\n    ULARGE_INTEGER uli = { 0 };\n    uli.LowPart = ft.dwLowDateTime;\n    uli.HighPart = ft.dwHighDateTime;\n    return uli.QuadPart;\n}\n\nbool CPUStats::UpdateCPUData()\n{\n    #define NUMBER_OF_PROCESSORS (8)\n    #define PROCESSOR_BUFFER_SIZE (NUMBER_OF_PROCESSORS * 8)\n    static ULONG64 ProcessorIdleTimeBuffer [ PROCESSOR_BUFFER_SIZE ];\n\n    FILETIME IdleTime, KernelTime, UserTime;\n    static unsigned long long PrevTotal = 0;\n    static unsigned long long PrevIdle = 0;\n    static unsigned long long PrevUser = 0;\n    unsigned long long ThisTotal;\n    unsigned long long ThisIdle, ThisKernel, ThisUser;\n    unsigned long long TotalSinceLast, IdleSinceLast, UserSinceLast;\n\n\n    // GET THE KERNEL / USER / IDLE times.  \n    // And oh, BTW, kernel time includes idle time\n    GetSystemTimes( & IdleTime, & KernelTime, & UserTime);\n\n    ThisIdle = FileTimeToInt64(IdleTime);\n    ThisKernel = FileTimeToInt64 (KernelTime);\n    ThisUser = FileTimeToInt64 (UserTime);\n\n    ThisTotal = ThisKernel + ThisUser;\n    TotalSinceLast = ThisTotal - PrevTotal;\n    IdleSinceLast = ThisIdle - PrevIdle;\n    UserSinceLast = ThisUser - PrevUser;\n    double Headroom;\n    Headroom =  (double)IdleSinceLast / (double)TotalSinceLast ;\n    double Load;\n    Load = 1.0 - Headroom;\n    Headroom *= 100.0;  // to make it percent\n    Load *= 100.0;  // percent\n\n    PrevTotal = ThisTotal;\n    PrevIdle = ThisIdle;\n    PrevUser = ThisUser;\n\n    // print results to output window of VS when run in Debug\n    m_cpuDataTotal.percent = Load;\n    return true;\n}\n\nbool CPUStats::ReadcpuTempFile(int&) {\n    return false;\n}\n\nCPUStats::CPUStats()\n{\n}\nCPUStats::~CPUStats()\n{\n}\nCPUStats cpuStats;"
  },
  {
    "path": "src/dbus.cpp",
    "content": "#include <array>\n#include <cstdio>\n#include <iostream>\n#include <sstream>\n\n#include \"dbus_helpers.h\"\n#include \"dbus_info.h\"\n#include \"string_utils.h\"\n#include \"file_utils.h\"\n\nusing ms = std::chrono::milliseconds;\nusing namespace DBus_helpers;\n#define DBUS_TIMEOUT 2000  // ms\n\nstruct mutexed_metadata main_metadata;\n\nnamespace dbusmgr {\ndbus_manager dbus_mgr;\n}\n\ntemplate <class T>\nstatic void assign_metadata_value(metadata& meta, const std::string& key,\n                                  const T& value) {\n    if (key == \"PlaybackStatus\") {\n        meta.playing = (value == \"Playing\");\n        meta.got_playback_data = true;\n    } else if (key == \"xesam:title\") {\n        meta.title = value;\n        meta.got_song_data = true;\n        meta.valid = true;\n    } else if (key == \"xesam:artist\") {\n        meta.artists = value;\n        meta.got_song_data = true;\n        meta.valid = true;\n    } else if (key == \"xesam:album\") {\n        meta.album = value;\n        meta.got_song_data = true;\n        meta.valid = true;\n    } else if (key == \"mpris:artUrl\") {\n        meta.artUrl = value;\n        meta.got_song_data = true;\n    } else if (key == \"xesam:url\") {\n        // HACK if there's no metadata then use this to clear old ones\n        meta.got_song_data = true;\n    }\n}\n\nstatic std::string format_signal(const dbusmgr::DBusSignal& s) {\n    std::stringstream ss;\n    ss << \"type='signal',interface='\" << s.intf << \"'\";\n    ss << \",member='\" << s.signal << \"'\";\n    return ss.str();\n}\n\nstatic void parse_song_data(DBusMessageIter_wrap iter, metadata& meta){\n    iter.string_map_for_each([&meta](const std::string& key,\n                                       DBusMessageIter_wrap it) {\n        std::string val;\n        if (it.is_primitive()) {\n            val = it.get_stringified();\n        } else if (it.is_array()) {\n            it.array_for_each_stringify([&](const std::string& str) {\n                if (val.empty()) {\n                    val = str;\n                } else {\n                    val += \", \" + str;\n                }\n            });\n        }\n        assign_metadata_value(meta, key, val);\n    });\n}\n\nstatic void parse_mpris_properties(libdbus_loader& dbus, DBusMessage* msg,\n                                   std::string& source, metadata& meta) {\n    /**\n     *  Expected response Format:\n     *      string,\n     *      map{\n     *          \"Metadata\" -> multimap,\n     *          \"PlaybackStatus\" -> string\n     *      }\n     */\n\n    auto iter = DBusMessageIter_wrap(msg, &dbus);\n    source = iter.get_primitive<std::string>();\n    if (source != \"org.mpris.MediaPlayer2.Player\") return;\n\n    iter.next();\n    if (!iter.is_array()) return;\n\n    iter.string_map_for_each([&meta](std::string& key, DBusMessageIter_wrap it) {\n        if (key == \"Metadata\") {\n            parse_song_data(it, meta);\n        } else if (key == \"PlaybackStatus\") {\n            auto val = it.get_stringified();\n            assign_metadata_value(meta, key, val);\n        }\n    });\n    meta.valid = (meta.artists.size() || !meta.title.empty());\n}\n\nstatic bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr,\n                         std::string& name_owner, const char* name) {\n    auto reply =\n        DBusMessage_wrap::new_method_call(\n            \"org.freedesktop.DBus\", \"/org/freedesktop/DBus\",\n            \"org.freedesktop.DBus\", \"GetNameOwner\", &dbus_mgr.dbus())\n            .argument(name)\n            .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);\n    if (!reply) return false;\n\n    auto iter = reply.iter();\n    if (!iter.is_string()) return false;\n    name_owner = iter.get_primitive<std::string>();\n    return true;\n}\n\nstatic bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta,\n                              const char* dest, const char* prop) {\n    auto reply =\n        DBusMessage_wrap::new_method_call(dest, \"/org/mpris/MediaPlayer2\",\n                                          \"org.freedesktop.DBus.Properties\",\n                                          \"Get\", &dbus_mgr.dbus())\n            .argument(\"org.mpris.MediaPlayer2.Player\")\n            .argument(prop)\n            .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);\n\n    if (!reply) return false;\n\n    auto iter = reply.iter();\n\n    if (iter.is_array()) {\n        parse_song_data(iter, meta);\n    } else if (iter.is_primitive()) {\n        assign_metadata_value(meta, prop, iter.get_stringified());\n    } else {\n        return false;\n    }\n    return true;\n}\n\nnamespace dbusmgr {\nbool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) {\n    if (name == \"\") name = m_active_player;\n    if (name == \"\") return false;\n    meta = {};\n    dbus_get_player_property(*this, meta, name.c_str(), \"Metadata\");\n    dbus_get_player_property(*this, meta, name.c_str(), \"PlaybackStatus\");\n    meta.valid = (meta.artists.size() || !meta.title.empty());\n    return true;\n}\n\nbool dbus_manager::init_internal() {\n    if (!m_dbus_ldr.IsLoaded() && !m_dbus_ldr.Load(\"libdbus-1.so.3\")) {\n        SPDLOG_ERROR(\"Could not load libdbus-1.so.3\");\n        return false;\n    }\n\n    m_dbus_ldr.error_init(&m_error);\n\n    m_dbus_ldr.threads_init_default();\n\n    if (nullptr ==\n        (m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error))) {\n        SPDLOG_ERROR(\"{}\", m_error.message);\n        m_dbus_ldr.error_free(&m_error);\n        return false;\n    }\n\n    SPDLOG_DEBUG(\"Connected to D-Bus as \\\"{}\\\"\",\n              m_dbus_ldr.bus_get_unique_name(m_dbus_conn));\n\n    m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals,\n                                     reinterpret_cast<void*>(this), nullptr);\n\n    start_thread();\n\n    dbus_list_name_to_owner();\n    m_inited = true;\n    return true;\n}\n\nbool dbus_manager::init(Service srv) {\n    if (!m_inited && !init_internal())\n        return false;\n\n    connect_to_signals(srv);\n    m_active_srvs |= srv;\n    return true;\n}\n\nbool dbus_manager::init_mpris(const std::string& requested_player) {\n    if (!requested_player.empty()) {\n        m_requested_player = \"org.mpris.MediaPlayer2.\" + requested_player;\n    } else\n        m_requested_player.clear();\n\n    if (m_active_srvs & SRV_MPRIS) {\n        select_active_player();\n        return true;\n    }\n\n    SPDLOG_WARN(\"D-Bus hasn't been inited yet.\");\n    return false;\n}\n\nbool dbus_manager::select_active_player() {\n    auto old_active_player = m_active_player;\n    m_active_player = \"\";\n    metadata meta {};\n    if (!m_requested_player.empty()) {\n        // If the requested player is available, use it\n        if (m_name_owners.count(m_requested_player) > 0) {\n            m_active_player = m_requested_player;\n            SPDLOG_DEBUG(\"Selecting requested player: {}\", m_requested_player);\n            get_media_player_metadata(meta, m_active_player);\n        }\n    } else {\n        // If no player is requested, use any player that is currently playing\n        if (m_active_player.empty()) {\n            auto it = std::find_if(m_name_owners.begin(), m_name_owners.end(), [this, &meta](auto& entry){\n                auto& name = entry.first;\n                this->get_media_player_metadata(meta, name);\n                if(meta.playing) {\n                    return true;\n                }\n                else {\n                    meta = {};\n                    return false;\n                }\n            });\n\n            if(it != m_name_owners.end()){\n                m_active_player = it->first;\n                SPDLOG_DEBUG(\"Selecting fallback player: {}\", m_active_player);\n            }\n        }\n    }\n\n    if (!m_active_player.empty()) {\n        onNewPlayer(meta);\n        return true;\n    } else {\n        SPDLOG_DEBUG(\"No active players\");\n        if (!old_active_player.empty()) {\n            onNoPlayer();\n        }\n        return false;\n    }\n}\n\nvoid dbus_manager::deinit(Service srv) {\n    if (!m_inited) return;\n\n    m_active_srvs &= ~srv;\n    if (m_dbus_conn)\n        disconnect_from_signals(srv);\n\n    // unreference system bus connection instead of closing it\n    if (m_dbus_conn && !m_active_srvs) {\n        m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals,\n                                            reinterpret_cast<void*>(this));\n        stop_thread();\n        m_dbus_ldr.connection_unref(m_dbus_conn);\n        m_dbus_conn = nullptr;\n        m_dbus_ldr.error_free(&m_error);\n        m_inited = false;\n    }\n}\n\ndbus_manager::~dbus_manager() { deinit(static_cast<Service>(m_active_srvs)); }\n\nDBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn,\n                                               DBusMessage* msg,\n                                               void* userData) {\n    auto& manager = *reinterpret_cast<dbus_manager*>(userData);\n\n    for (auto& sig : manager.m_signals) {\n        if (manager.m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal)) {\n            auto sender = manager.m_dbus_ldr.message_get_sender(msg);\n            if ((manager.*(sig.handler))(msg, sender))\n                return DBUS_HANDLER_RESULT_HANDLED;\n            else\n                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;\n        }\n    }\n    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;\n}\n\nbool dbus_manager::handle_properties_changed(DBusMessage* msg,\n                                             const char* sender) {\n    std::string source;\n\n    metadata meta;\n    parse_mpris_properties(m_dbus_ldr, msg, source, meta);\n#ifndef NDEBUG\n    std::cerr << \"PropertiesChanged Signal received:\\n\";\n    std::cerr << \"\\tSource: \" << source << \"\\n\";\n    std::cerr << \"active_player:         \" << m_active_player << \"\\n\";\n    std::cerr << \"active_player's owner: \" << m_name_owners[m_active_player]\n              << \"\\n\";\n    std::cerr << \"sender:                \" << sender << \"\\n\";\n#endif\n    if (source != \"org.mpris.MediaPlayer2.Player\") return false;\n\n    if (m_active_player == \"\" ||\n        (m_requested_player.empty() && !main_metadata.meta.playing)) {\n        select_active_player();\n    }\n    else if (m_name_owners[m_active_player] == sender) {\n        onPlayerUpdate(meta);\n    }\n    return true;\n}\n\nbool dbus_manager::handle_name_owner_changed(DBusMessage* _msg,\n                                             const char* sender) {\n    std::vector<std::string> str;\n\n    for (auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr); iter;\n         iter.next()) {\n        str.push_back(iter.get_primitive<std::string>());\n    }\n\n    // register new name\n    if (str.size() == 3 && starts_with(str[0], \"org.mpris.MediaPlayer2.\") &&\n        !str[2].empty()) {\n        m_name_owners[str[0]] = str[2];\n        if (str[0] == m_requested_player) {\n            select_active_player();\n        }\n    }\n\n    // did a player quit?\n    if (str[2].empty()) {\n        if (str.size() == 3 && str[0] == m_active_player) {\n            m_name_owners.erase(str[0]);\n            select_active_player();\n        }\n    }\n    return true;\n}\n\nbool dbus_manager::gamemode_enabled(pid_t pid) {\n    if (!m_inited)\n        return false;\n\n    static int isvc = file_exists(\"/.flatpak-info\") ? 1 : 0;\n    const struct dbus_ep\n    {\n        const char *name;\n        const char *path;\n        const char *iface;\n    } svc[] {\n        {\n            \"com.feralinteractive.GameMode\",\n            \"/com/feralinteractive/GameMode\",\n            \"com.feralinteractive.GameMode\"\n        },\n        {\n            \"org.freedesktop.portal.Desktop\",\n            \"/org/freedesktop/portal/desktop\",\n            \"org.freedesktop.portal.GameMode\"\n        }\n    };\n\n    auto reply =\n        DBusMessage_wrap::new_method_call(\n            svc[isvc].name, svc[isvc].path, svc[isvc].iface,\n            \"QueryStatus\", &dbus_mgr.dbus())\n            .argument(pid)\n            .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);\n    if (!reply) return false;\n\n    auto iter = reply.iter();\n    if (!iter.is_signed()) return false;\n    return !!iter.get_primitive<int32_t>();\n}\n\nbool dbus_manager::handle_game_registered(DBusMessage* _msg,\n                                             const char* sender) {\n    auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr);\n    auto pid = iter.get_primitive<int32_t>();\n    iter.next();\n    auto path = iter.get_primitive<std::string>();\n    SPDLOG_INFO(\"Game registered: {} '{}'\", pid, path);\n    return true;\n}\n\nbool dbus_manager::handle_game_unregistered(DBusMessage* _msg,\n                                             const char* sender) {\n    auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr);\n    auto pid = iter.get_primitive<int32_t>();\n    iter.next();\n    auto path = iter.get_primitive<std::string>();\n    SPDLOG_INFO(\"Game unregistered: {} '{}'\", pid, path);\n    return true;\n}\n\nvoid dbus_manager::connect_to_signals(Service srv) {\n    for (auto kv : m_signals) {\n        if (!(kv.srv & srv)) continue;\n        auto signal = format_signal(kv);\n        m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error);\n        if (m_dbus_ldr.error_is_set(&m_error)) {\n            SPDLOG_ERROR(\"{}: {}\", m_error.name, m_error.message);\n            m_dbus_ldr.error_free(&m_error);\n            // return;\n        }\n    }\n}\n\nvoid dbus_manager::disconnect_from_signals(Service srv) {\n    for (auto kv : m_signals) {\n        if (!(kv.srv & srv)) continue;\n        auto signal = format_signal(kv);\n        m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);\n        if (m_dbus_ldr.error_is_set(&m_error)) {\n#ifndef NDEBUG\n            // spdlog might be destroyed by now\n            std::cerr << \"[MANGOHUD] [debug] \" << __func__ << \" \"\n            << m_error.name << \": \" << m_error.message << std::endl;\n#endif\n            m_dbus_ldr.error_free(&m_error);\n        }\n    }\n}\n\nbool dbus_manager::dbus_list_name_to_owner() {\n    auto reply =\n        DBusMessage_wrap::new_method_call(\n            \"org.freedesktop.DBus\", \"/org/freedesktop/DBus\",\n            \"org.freedesktop.DBus\", \"ListNames\", &dbus_mgr.dbus())\n            .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);\n    if (!reply) return false;\n\n    auto iter = reply.iter();\n\n    if (!iter.is_array()) {\n        return false;\n    }\n    iter.array_for_each_value<std::string>([&](std::string name) {\n        if (!starts_with(name, \"org.mpris.MediaPlayer2.\")) return;\n        std::string owner;\n        if (dbus_get_name_owner(dbus_mgr, owner, name.c_str())) {\n            m_name_owners[name] = owner;\n        }\n    });\n    return true;\n}\n\nvoid dbus_manager::stop_thread() {\n    m_quit = true;\n    if (m_thread.joinable()) m_thread.join();\n}\n\nvoid dbus_manager::start_thread() {\n    stop_thread();\n    m_quit = false;\n    m_thread = std::thread(&dbus_manager::dbus_thread, this);\n    pthread_setname_np(m_thread.native_handle(), \"mangohud-dbus\");\n}\n\nvoid dbus_manager::dbus_thread() {\n    using namespace std::chrono_literals;\n    while (!m_quit && m_dbus_ldr.connection_read_write_dispatch(m_dbus_conn, 0))\n        std::this_thread::sleep_for(10ms);\n}\n\nvoid dbus_manager::onNoPlayer() {\n    std::lock_guard<std::mutex> lck(main_metadata.mtx);\n    main_metadata.meta = {};\n    main_metadata.ticker = {};\n}\n\nvoid dbus_manager::onNewPlayer(metadata& meta) {\n    std::lock_guard<std::mutex> lck(main_metadata.mtx);\n    main_metadata.meta = meta;\n    main_metadata.ticker = {};\n}\n\nvoid dbus_manager::onPlayerUpdate(metadata& meta) {\n    std::lock_guard<std::mutex> lck(main_metadata.mtx);\n    if (meta.got_song_data) {\n        // If the song has changed, reset the ticker\n        if (main_metadata.meta.artists != meta.artists ||\n            main_metadata.meta.album != meta.album ||\n            main_metadata.meta.title != meta.title) {\n            main_metadata.ticker = {};\n        }\n\n        main_metadata.meta = meta;\n        main_metadata.meta.playing = true;\n    }\n    if (meta.got_playback_data) {\n        main_metadata.meta.playing = meta.playing;\n    }\n}\n\n}  // namespace dbusmgr\n"
  },
  {
    "path": "src/dbus_helpers.h",
    "content": "#pragma once\n#ifndef MANGOHUD_DBUS_HELPERS\n#define MANGOHUD_DBUS_HELPERS\n\n#include <vector>\n#include <spdlog/spdlog.h>\n#include <signal.h>\n\n#include \"loaders/loader_dbus.h\"\n\nnamespace DBus_helpers {\nnamespace detail {\n// clang-format off\ntemplate<class T> struct dbus_type_traits{};\ntemplate<> struct dbus_type_traits<bool>        { const int value = DBUS_TYPE_BOOLEAN; const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<uint8_t>     { const int value = DBUS_TYPE_BYTE;    const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<uint16_t>    { const int value = DBUS_TYPE_UINT16;  const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<uint32_t>    { const int value = DBUS_TYPE_UINT32;  const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<uint64_t>    { const int value = DBUS_TYPE_UINT64;  const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<int16_t>     { const int value = DBUS_TYPE_INT16;   const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<int32_t>     { const int value = DBUS_TYPE_INT32;   const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<int64_t>     { const int value = DBUS_TYPE_INT64;   const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<double>      { const int value = DBUS_TYPE_DOUBLE;  const bool is_fixed = true; };\ntemplate<> struct dbus_type_traits<const char*> { const int value = DBUS_TYPE_STRING;  const bool is_fixed = false; };\n// clang-format on\n\ntemplate <class T>\nconst int dbus_type_identifier = dbus_type_traits<T>().value;\n\ntemplate <class T>\nconst bool is_fixed = dbus_type_traits<T>().is_fixed;\n}  // namespace detail\n\nclass DBusMessageIter_wrap {\n   public:\n    DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader);\n    DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader);\n\n    //  Type accessors\n    int type() const noexcept { return m_type; }\n    bool is_unsigned() const noexcept;\n    bool is_signed() const noexcept;\n    bool is_string() const noexcept;\n    bool is_double() const noexcept;\n    bool is_primitive() const noexcept;\n    bool is_array() const noexcept;\n    operator bool() const noexcept { return type() != DBUS_TYPE_INVALID; }\n\n    //  Value accessors\n    //  Primitives\n    template <class T>\n    auto get_primitive() -> T;\n    auto get_unsigned() -> uint64_t;\n    auto get_signed() -> int64_t;\n    auto get_stringified() -> std::string;\n    //  Composites\n    auto get_array_iter() -> DBusMessageIter_wrap;\n    auto get_dict_entry_iter() -> DBusMessageIter_wrap;\n\n    //  Looping\n    template <class Callable>\n    void array_for_each(Callable);\n    template <class Callable>\n    void array_for_each_stringify(Callable);\n    template <class T, class Callable>\n    void array_for_each_value(Callable);\n\n    template <class Callable>\n    void string_map_for_each(Callable);\n    template <class Callable>\n    void string_multimap_for_each_stringify(Callable);\n\n    auto next() -> DBusMessageIter_wrap&;\n\n   private:\n    DBusMessageIter resolve_variants() {\n        auto iter = m_Iter;\n        auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter);\n        while (field_type == DBUS_TYPE_VARIANT) {\n            m_DBus->message_iter_recurse(&iter, &iter);\n            field_type = m_DBus->message_iter_get_arg_type(&iter);\n        }\n        return iter;\n    }\n\n    DBusMessageIter m_Iter;\n    DBusMessageIter m_resolved_iter;\n    int m_type;\n    libdbus_loader* m_DBus;\n};\n\nDBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessage* msg,\n                                           libdbus_loader* loader) {\n    m_DBus = loader;\n    if (msg) {\n        m_DBus->message_iter_init(msg, &m_Iter);\n        m_resolved_iter = resolve_variants();\n        m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);\n    } else {\n        m_type = DBUS_TYPE_INVALID;\n    }\n}\n\nDBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessageIter iter,\n                                           libdbus_loader* loader)\n    : m_Iter(iter), m_DBus(loader) {\n    m_resolved_iter = resolve_variants();\n    m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);\n}\n\nbool DBusMessageIter_wrap::is_unsigned() const noexcept {\n    return ((type() == DBUS_TYPE_BYTE) || (type() == DBUS_TYPE_INT16) ||\n            (type() == DBUS_TYPE_INT32) || (type() == DBUS_TYPE_INT64));\n}\n\nbool DBusMessageIter_wrap::is_signed() const noexcept {\n    return ((type() == DBUS_TYPE_INT16) || (type() == DBUS_TYPE_INT32) ||\n            (type() == DBUS_TYPE_INT64));\n}\n\nbool DBusMessageIter_wrap::is_string() const noexcept {\n    return (type() == DBUS_TYPE_STRING);\n}\n\nbool DBusMessageIter_wrap::is_double() const noexcept {\n    return (type() == DBUS_TYPE_DOUBLE);\n}\n\nbool DBusMessageIter_wrap::is_primitive() const noexcept {\n    return (is_double() || is_signed() || is_unsigned() || is_string());\n}\n\nbool DBusMessageIter_wrap::is_array() const noexcept {\n    return (type() == DBUS_TYPE_ARRAY);\n}\n\ntemplate <class T>\nauto DBusMessageIter_wrap::get_primitive() -> T {\n    auto requested_type = detail::dbus_type_identifier<T>;\n    if (type() == DBUS_TYPE_OBJECT_PATH && requested_type == DBUS_TYPE_STRING) {\n        // no special type, just a string\n    }\n    else if (requested_type != type()) {\n        SPDLOG_ERROR(\"Type mismatch: '{}' vs '{}'\",\n                  ((char)requested_type), (char)type());\n#ifndef NDEBUG\n        raise(SIGTRAP);\n#endif\n        return T();\n    }\n\n    T ret;\n    m_DBus->message_iter_get_basic(&m_resolved_iter, &ret);\n    return ret;\n}\n\ntemplate <>\nauto DBusMessageIter_wrap::get_primitive<std::string>() -> std::string {\n    auto s = get_primitive<const char*>();\n    if (!s)\n        return std::string();\n    return std::string(s);\n}\n\nuint64_t DBusMessageIter_wrap::get_unsigned() {\n    auto t = type();\n    switch (t) {\n        case DBUS_TYPE_BYTE:\n            return get_primitive<uint8_t>();\n        case DBUS_TYPE_UINT16:\n            return get_primitive<uint16_t>();\n        case DBUS_TYPE_UINT32:\n            return get_primitive<uint32_t>();\n        case DBUS_TYPE_UINT64:\n            return get_primitive<uint64_t>();\n        default:\n            return 0;\n    }\n}\n\nint64_t DBusMessageIter_wrap::get_signed() {\n    auto t = type();\n    switch (t) {\n        case DBUS_TYPE_INT16:\n            return get_primitive<int16_t>();\n        case DBUS_TYPE_INT32:\n            return get_primitive<int32_t>();\n        case DBUS_TYPE_INT64:\n            return get_primitive<int64_t>();\n        default:\n            return 0;\n    }\n}\n\nauto DBusMessageIter_wrap::get_stringified() -> std::string {\n    if (is_string()) return get_primitive<std::string>();\n    if (is_unsigned()) return std::to_string(get_unsigned());\n    if (is_signed()) return std::to_string(get_signed());\n    if (is_double()) return std::to_string(get_primitive<double>());\n    SPDLOG_ERROR(\"stringify failed\");\n    return std::string();\n}\n\nauto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {\n    if (!is_array()) {\n        SPDLOG_ERROR(\"Not an array; {}\", (char)type());\n        return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);\n    }\n\n    DBusMessageIter ret;\n    m_DBus->message_iter_recurse(&m_resolved_iter, &ret);\n    return DBusMessageIter_wrap(ret, m_DBus);\n}\n\nauto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap {\n    if (type() != DBUS_TYPE_DICT_ENTRY) {\n        SPDLOG_ERROR(\"Not a dict entry {}\", (char)type());\n        return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);\n    }\n\n    DBusMessageIter ret;\n    m_DBus->message_iter_recurse(&m_resolved_iter, &ret);\n    return DBusMessageIter_wrap(ret, m_DBus);\n}\n\ntemplate <class T, class Callable>\nvoid DBusMessageIter_wrap::array_for_each_value(Callable action) {\n    auto iter = get_array_iter();\n    for (; iter; iter.next()) {\n        action(iter.get_primitive<T>());\n    }\n}\n\ntemplate <class Callable>\nvoid DBusMessageIter_wrap::array_for_each(Callable action) {\n    auto iter = get_array_iter();\n    for (; iter; iter.next()) {\n        action(iter);\n    }\n}\n\ntemplate <class Callable>\nvoid DBusMessageIter_wrap::array_for_each_stringify(Callable action) {\n    auto iter = get_array_iter();\n    for (; iter; iter.next()) {\n        action(iter.get_stringified());\n    }\n}\n\ntemplate <class T>\nvoid DBusMessageIter_wrap::string_map_for_each(T action) {\n    auto iter = get_array_iter();\n    for (; iter; iter.next()) {\n        auto it = iter.get_dict_entry_iter();\n        auto key = it.get_primitive<std::string>();\n\n        it.next();\n        action(key, it);\n    }\n}\n\ntemplate <class T>\nvoid DBusMessageIter_wrap::string_multimap_for_each_stringify(T action) {\n    string_map_for_each([&action](const std::string& key, DBusMessageIter_wrap it) {\n        if (it.is_array()) {\n            it.array_for_each_stringify(\n                [&](const std::string& val) { action(key, val); });\n        } else if (it.is_primitive()) {\n            action(key, it.get_stringified());\n        }\n    });\n}\n\nauto DBusMessageIter_wrap::next() -> DBusMessageIter_wrap& {\n    if (!*this) return *this;\n    m_DBus->message_iter_next(&m_Iter);\n    // Resolve any variants\n    m_resolved_iter = resolve_variants();\n    m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);\n    return *this;\n}\n\n\nclass DBusMessage_wrap {\n   public:\n    DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false)\n        : m_owning(owning), m_msg(msg), m_DBus(ldr) {}\n\n    ~DBusMessage_wrap() { free_if_owning(); }\n\n    DBusMessage_wrap(const DBusMessage_wrap&) = delete;\n    DBusMessage_wrap(DBusMessage_wrap&&) = default;\n\n    operator bool() const noexcept { return m_msg != nullptr; }\n\n    template <class T>\n    DBusMessage_wrap& argument(T arg);\n\n    DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn,\n                                               int timeout);\n\n    DBusMessageIter_wrap iter() { return DBusMessageIter_wrap(m_msg, m_DBus); }\n\n    static DBusMessage_wrap new_method_call(const std::string& bus_name,\n                                            const std::string& path,\n                                            const std::string& iface,\n                                            const std::string& method,\n                                            libdbus_loader* loader);\n\n   private:\n    void free_if_owning();\n    bool m_owning;\n    DBusMessage* m_msg;\n    libdbus_loader* m_DBus;\n    std::vector<std::string> m_args;\n};\n\ntemplate <class T>\nDBusMessage_wrap& DBusMessage_wrap::argument(T arg) {\n    if (!m_msg) return *this;\n    if (!m_DBus->message_append_args(m_msg, detail::dbus_type_identifier<T>,\n                                        &arg, DBUS_TYPE_INVALID)) {\n        free_if_owning();\n    }\n    return *this;\n}\n\ntemplate <>\nDBusMessage_wrap& DBusMessage_wrap::argument<const std::string&>(\n    const std::string& str) {\n    return argument<const char*>(str.c_str());\n}\n\nDBusMessage_wrap DBusMessage_wrap::send_with_reply_and_block(\n    DBusConnection* conn, int timeout) {\n    if (!m_msg) {\n        return DBusMessage_wrap(nullptr, m_DBus);\n    }\n    DBusError err;\n    m_DBus->error_init(&err);\n    auto reply = m_DBus->connection_send_with_reply_and_block(conn, m_msg,\n                                                              timeout, &err);\n    if (reply == nullptr) {\n        SPDLOG_ERROR(\"[{}]: {}\", __func__, err.message);\n        free_if_owning();\n        m_DBus->error_free(&err);\n    }\n    return DBusMessage_wrap(reply, m_DBus, true);\n}\n\nDBusMessage_wrap DBusMessage_wrap::new_method_call(const std::string& bus_name,\n                                                   const std::string& path,\n                                                   const std::string& iface,\n                                                   const std::string& method,\n                                                   libdbus_loader* loader) {\n    auto msg = loader->message_new_method_call(\n        (bus_name.empty()) ? nullptr : bus_name.c_str(), path.c_str(),\n        (iface.empty()) ? nullptr : iface.c_str(), method.c_str());\n    return DBusMessage_wrap(msg, loader, true);\n}\n\nvoid DBusMessage_wrap::free_if_owning() {\n    if (m_msg and m_owning) {\n        m_DBus->message_unref(m_msg);\n    }\n    m_msg = nullptr;\n}\n}  // namespace DBus_helpers\n\n#endif  // MANGOHUD_DBUS_HELPERS\n"
  },
  {
    "path": "src/dbus_info.h",
    "content": "#pragma once\n#ifndef MANGOHUD_DBUS_INFO_H\n#define MANGOHUD_DBUS_INFO_H\n\n#ifdef HAVE_DBUS\n\n#include <array>\n#include <functional>\n#include <map>\n#include <mutex>\n#include <stdexcept>\n#include <string>\n#include <thread>\n#include <unordered_map>\n#include <vector>\n\n#include \"loaders/loader_dbus.h\"\n\nstruct metadata {\n    // std::vector<std::string> artists;\n    std::string artists;  // pre-concatenate\n    std::string title;\n    std::string album;\n    std::string something;\n    std::string artUrl;\n    bool playing = false;\n\n    bool valid = false;\n    bool got_song_data = false;\n    bool got_playback_data = false;\n};\n\nstruct mp_fmt\n{\n    std::string text;\n    float width;\n};\n\nstruct mutexed_metadata {\n    std::mutex mtx;\n    metadata meta;\n    struct {\n        float pos;\n        float longest;\n        int dir = -1;\n        bool needs_recalc = true;\n\n        std::vector<mp_fmt> formatted;\n    } ticker;\n};\n\nenum SignalType {\n    ST_NAMEOWNERCHANGED,\n    ST_PROPERTIESCHANGED,\n};\n\nextern struct mutexed_metadata main_metadata;\n\nnamespace dbusmgr {\n\nclass dbus_manager;\nusing signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*);\n\nenum Service\n{\n    SRV_NONE        = 0,\n    SRV_MPRIS       = (1ul << 0),\n    SRV_GAMEMODE    = (1ul << 1),\n    SRV_ALL         = 0xFFFFFFFF,\n};\n\nstruct DBusSignal {\n    Service srv;\n    const char* intf;\n    const char* signal;\n    signal_handler_func handler;\n};\n\nclass dbus_manager {\n   public:\n    dbus_manager() {}\n\n    ~dbus_manager();\n\n    bool init(Service srv);\n    bool init_mpris(const std::string& requested_player);\n    void deinit(Service srv);\n    bool get_media_player_metadata(metadata& meta, std::string name = \"\");\n    void connect_to_signals(Service srv);\n    void disconnect_from_signals(Service srv);\n    DBusConnection* get_conn() const { return m_dbus_conn; }\n\n    bool gamemode_enabled(pid_t pid);\n\n    libdbus_loader& dbus() { return m_dbus_ldr; }\n\n   protected:\n    bool init_internal();\n    void stop_thread();\n    void start_thread();\n    void dbus_thread();\n\n    bool dbus_list_name_to_owner();\n    bool select_active_player();\n\n    static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*,\n                                            void*);\n\n    bool handle_properties_changed(DBusMessage*, const char*);\n    bool handle_name_owner_changed(DBusMessage*, const char*);\n    bool handle_game_registered(DBusMessage*, const char*);\n    bool handle_game_unregistered(DBusMessage*, const char*);\n\n    void onNewPlayer(\n        metadata& meta);  // A different player has become the active player\n    void onNoPlayer();    // There is no longer any player active\n    void onPlayerUpdate(\n        metadata& meta);  // The active player has sent an update\n\n    DBusError m_error;\n    DBusConnection* m_dbus_conn = nullptr;\n    bool m_quit = false;\n    bool m_inited = false;\n    std::thread m_thread;\n    libdbus_loader m_dbus_ldr;\n    std::unordered_map<std::string, std::string> m_name_owners;\n    std::string m_requested_player;\n    std::string m_active_player;\n    uint32_t m_active_srvs = SRV_NONE;\n\n    const std::array<DBusSignal, 2> m_signals{{\n        {SRV_MPRIS, \"org.freedesktop.DBus\", \"NameOwnerChanged\",\n         &dbus_manager::handle_name_owner_changed},\n        {SRV_MPRIS, \"org.freedesktop.DBus.Properties\", \"PropertiesChanged\",\n         &dbus_manager::handle_properties_changed},\n//         {SRV_GAMEMODE, \"com.feralinteractive.GameMode\", \"GameRegistered\",\n//          &dbus_manager::handle_game_registered},\n//         {SRV_GAMEMODE, \"com.feralinteractive.GameMode\", \"GameUnregistered\",\n//          &dbus_manager::handle_game_unregistered},\n    }};\n};\n\nextern dbus_manager dbus_mgr;\n}  // namespace dbusmgr\nbool get_media_player_metadata(dbusmgr::dbus_manager& dbus, const std::string& name, metadata& meta);\n\n#endif // HAVE_DBUS\n#endif //MANGOHUD_DBUS_INFO_H\n"
  },
  {
    "path": "src/device.cpp",
    "content": "#include \"device.h\"\n#include <filesystem.h>\n#include <iostream>\n#include <algorithm>\n#include <spdlog/spdlog.h>\n\nnamespace fs = ghc::filesystem;\nusing namespace std;\nstd::mutex device_lock;\nstd::vector<device_batt> device_data;\nstd::vector<std::string> list;\nbool device_found = false;\nbool check_gamepad = false;\nbool check_mouse = false;\nint  device_count = 0;\nint xbox_count = 0;\nint ds4_count = 0;\nint ds5_count = 0;\nint switch_count = 0;\nint bitdo_count = 0;\nint logi_count = 0; //Logitech devices, mice & keyboards etc.\nint shield_count = 0;\n\nstd::string  xbox_paths [2]{\"gip\",\"xpadneo\"};\n\nstatic bool operator<(const device_batt& a, const device_batt& b)\n{\n    return a.name < b.name;\n}\n\n\nvoid device_update(const struct overlay_params& params){\n    std::unique_lock<std::mutex> l(device_lock);\n    fs::path path(\"/sys/class/power_supply\");\n    list.clear();\n    xbox_count = 0;\n    ds4_count = 0;\n    ds5_count = 0;\n    switch_count = 0;\n    bitdo_count = 0;\n    shield_count = 0;\n    for (auto &p : fs::directory_iterator(path)) {\n        string fileName = p.path().filename();\n//Gamepads\n        if (std::find(params.device_battery.begin(), params.device_battery.end(), \"gamepad\") != params.device_battery.end()){\n            check_gamepad = true;\n            //CHECK XONE AND XPADNEO DEVICES\n            for (string n : xbox_paths ) {\n                if (fileName.find(n) != std::string::npos) {\n                    list.push_back(p.path());\n                    device_found = true;\n                    xbox_count += 1;\n                }\n            }\n            //CHECK FOR DUAL SHOCK 4 DEVICES\n            if (fileName.find(\"sony_controller\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n                ds4_count +=1 ;\n            }\n            if (fileName.find(\"ps-controller\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n                ds5_count +=1 ;\n            }\n            //CHECK FOR NINTENDO SWITCH DEVICES\n            if (fileName.find(\"nintendo_switch_controller\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n                switch_count += 1;\n            }\n            //CHECK * BITDO DEVICES\n            if (fileName.find(\"hid-e4\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n                bitdo_count += 1;\n            }\n            //CHECK NVIDIA SHIELD DEVICES\n            if (fileName.find(\"thunderstrike\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n                shield_count += 1;\n            }\n        }\n\n// Mice and Keyboards\n        //CHECK LOGITECH DEVICES\n         if (std::find(params.device_battery.begin(), params.device_battery.end(), \"mouse\") != params.device_battery.end()) {\n            check_mouse = true;\n            if (fileName.find(\"hidpp_battery\") != std::string::npos) {\n                list.push_back(p.path());\n                device_found = true;\n            }\n         }\n    }\n}\n\n\nvoid device_info () {\n    std::unique_lock<std::mutex> l(device_lock);\n    device_count = 0;\n    device_data.clear();\n    //gamepad counters\n    int xbox_counter = 0;\n    int ds4_counter = 0;\n    int ds5_counter = 0;\n    int switch_counter = 0;\n    int bitdo_counter = 0;\n    int shield_counter = 0;\n\n    for (auto &path : list ) {\n        //Set devices paths\n        std::string capacity = path + \"/capacity\";\n        std::string capacity_level = path + \"/capacity_level\";\n        std::string status = path + \"/status\";\n        std::string model = path + \"/model_name\";\n        std::ifstream input_capacity(capacity);\n        std::ifstream input_capacity_level(capacity_level);\n        std::ifstream input_status(status);\n        std::ifstream device_name(model);\n        std::string line;\n\n        device_data.push_back(device_batt());\n\n// GAMEPADS\n        //Xone and xpadneo devices\n        if (check_gamepad == true) {\n            if (path.find(\"gip\") != std::string::npos || path.find(\"xpadneo\") != std::string::npos) {\n                if (xbox_count == 1 )\n                    device_data[device_count].name = \"XBOX PAD\";\n                else\n                    device_data[device_count].name = \"XBOX PAD-\" + to_string(xbox_counter + 1);\n                xbox_counter++;\n            }\n            //DualShock 4 devices\n            if (path.find(\"sony_controller\") != std::string::npos) {\n                if (ds4_count == 1)\n                    device_data[device_count].name = \"DS4 PAD\";\n                else\n                    device_data[device_count].name = \"DS4 PAD-\" + to_string(ds4_counter + 1);\n                ds4_counter++;\n            }\n            //DualSense 5 devices\n            //Dual Shock 4 added to hid-playstation in Linux 6.2\n            if (path.find(\"ps-controller\") != std::string::npos) {\n                if (ds5_count == 1)\n                    device_data[device_count].name = \"DS4/5 PAD\";\n                else\n                    device_data[device_count].name = \"DS4/5 PAD-\" + to_string(ds5_counter + 1);\n                ds5_counter++;\n            }\n            //Nintendo Switch devices\n            if (path.find(\"nintendo_switch_controller\") != std::string::npos) {\n                if (switch_count == 1)\n                    device_data[device_count].name = \"SWITCH PAD\";\n                else\n                    device_data[device_count].name = \"SWITCH PAD-\" + to_string(switch_counter + 1);\n                switch_counter++;\n            }\n            //8bitdo devices\n            if (path.find(\"hid-e4\") != std::string::npos) {\n                if (bitdo_count == 1)\n                    device_data[device_count].name = \"8BITDO PAD\";\n                else\n                    device_data[device_count].name = \"8BITDO PAD-\" + to_string(bitdo_counter + 1);\n                bitdo_counter++;\n            }\n            //Shield devices\n            if (path.find(\"thunderstrike\") != std::string::npos) {\n                if (shield_count == 1)\n                    device_data[device_count].name = \"SHIELD PAD\";\n                else\n                    device_data[device_count].name = \"SHIELD PAD-\" + to_string(shield_counter + 1);\n                shield_counter++;\n            }\n        }\n\n// MICE AND KEYBOARDS\n        //Logitech Devices\n         if (check_mouse == true) {\n            if (path.find(\"hidpp_battery\") != std::string::npos) {\n                // Find a good way truncate name or retreive device type before using this\n                    // if (std::getline(device_name, line)) {\n                    //     device_data[device_count].name = line;\n                    // }\n                device_data[device_count].name = \"LOGI MOUSE/KB\";\n            }\n         }\n\n        //Get device charging status\n        if (std::getline(input_status, line)) {\n            if (line == \"Charging\" || line == \"Full\")\n                 device_data[device_count].is_charging = true;\n        }\n        //Get device Battery\n        if (fs::exists(capacity)) {\n            if (std::getline(input_capacity, line)) {\n                device_data[device_count].battery_percent = line;\n                device_data[device_count].report_percent = true;\n                switch(std::stoi(line)) {\n                    case 0 ... 25:\n                        device_data[device_count].battery = \"Low\";\n                        break;\n                    case 26 ... 49:\n                        device_data[device_count].battery = \"Normal\";\n                        break;\n                    case 50 ... 74:\n                        device_data[device_count].battery = \"High\";\n                        break;\n                    case 75 ... 100:\n                        device_data[device_count].battery = \"Full\";\n                        break;\n                }\n            }\n        }\n        else {\n            if (std::getline(input_capacity_level, line)) {\n                device_data[device_count].battery = line;\n            }\n        }\n        std::sort(device_data.begin(), device_data.end());\n        device_count += 1;\n\n    }\n}\n"
  },
  {
    "path": "src/device.h",
    "content": "#pragma once\n#ifndef MANGOHUD_DEVICE_H\n#define MANGOHUD_DEVICE_H\n#include <vector>\n#include <string>\n#include \"overlay_params.h\"\nstruct overlay_params;\nstruct device_batt {\n    std::string battery;\n    std::string name;\n    bool report_percent;\n    std::string battery_percent;\n    bool is_charging;\n};\n\nextern std::vector<device_batt> device_data;\nextern std::mutex device_lock;\n\nextern bool device_found;\nextern int device_count;\nvoid device_update(const overlay_params& params);\nvoid device_info();\n\n\n#endif // MANGOHUD_DEVICE_H\n"
  },
  {
    "path": "src/elfhacks.c",
    "content": "/**\n * \\file src/elfhacks.c\n * \\brief various ELF run-time hacks\n * \\author Pyry Haulos <pyry.haulos@gmail.com>\n * \\date 2007-2008\n * For conditions of distribution and use, see copyright notice in elfhacks.h\n */\n\n#ifndef _GNU_SOURCE\n#define _GNU_SOURCE\n#endif\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <errno.h>\n#include <elf.h>\n#include <link.h>\n#include <fnmatch.h>\n#include \"elfhacks.h\"\n\n#ifndef __ELF_NATIVE_CLASS\n#include \"sys/reg.h\"\n#define __ELF_NATIVE_CLASS __WORDSIZE\n#endif\n\n/**\n *  \\addtogroup elfhacks\n *  \\{\n */\n\n#if defined(__GLIBC__) && !(defined(__riscv) || defined(__mips__))\n# define ABS_ADDR(obj, ptr) (ptr)\n#else\n# define ABS_ADDR(obj, ptr) ((obj->addr) + (ptr))\n#endif\n\nstruct eh_iterate_callback_args {\n\teh_iterate_obj_callback_func callback;\n\tvoid *arg;\n};\n\nint eh_check_addr(eh_obj_t *obj, const void *addr);\nint eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr);\nint eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next);\nint eh_init_obj(eh_obj_t *obj);\n\nint eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val);\nint eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val);\n\nint eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg);\nint eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg);\nint eh_iterate_callback(struct dl_phdr_info *info, size_t size, void *argptr);\n\nint eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym);\nint eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym);\n\nElfW(Word) eh_hash_elf(const char *name);\nElf32_Word eh_hash_gnu(const char *name);\n\nint eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr)\n{\n\teh_obj_t *find = (eh_obj_t *) argptr;\n\n\tif (find->name == NULL) {\n\t\tif (strcmp(info->dlpi_name, \"\"))\n\t\t\treturn 0;\n\t} else if (fnmatch(find->name, info->dlpi_name, 0))\n\t\treturn 0;\n\n\tif (find->name == NULL) /* TODO readlink? */\n\t\tfind->name = \"/proc/self/exe\";\n\telse\n\t\tfind->name = info->dlpi_name;\n\tfind->addr = info->dlpi_addr;\n\n\t/* segment headers */\n\tfind->phdr = info->dlpi_phdr;\n\tfind->phnum = info->dlpi_phnum;\n\n\treturn 0;\n}\n\nint eh_iterate_callback(struct dl_phdr_info *info, size_t size, void *argptr)\n{\n\tstruct eh_iterate_callback_args *args = argptr;\n\teh_obj_t obj;\n\tint ret = 0;\n\n\t/* eh_init_obj needs phdr and phnum */\n\tobj.phdr = info->dlpi_phdr;\n\tobj.phnum = info->dlpi_phnum;\n\tobj.addr = info->dlpi_addr;\n\tobj.name = info->dlpi_name;\n\n\tif ((ret = eh_init_obj(&obj))) {\n\t\tif (ret == ENOTSUP) /* just skip */\n\t\t\treturn 0;\n\t\treturn ret;\n\t}\n\n\tif ((ret = args->callback(&obj, args->arg)))\n\t\treturn ret;\n\n\tif ((ret = eh_destroy_obj(&obj)))\n\t\treturn ret;\n\n\treturn 0;\n}\n\nint eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg)\n{\n\tint ret;\n\tstruct eh_iterate_callback_args args;\n\n\targs.callback = callback;\n\targs.arg = arg;\n\n\tif ((ret = dl_iterate_phdr(eh_iterate_callback, &args)))\n\t\treturn ret;\n\n\treturn 0;\n}\n\nint eh_find_obj(eh_obj_t *obj, const char *soname)\n{\n\t/* This function uses glibc-specific dl_iterate_phdr().\n\t   Another way could be parsing /proc/self/exe or using\n\t   pmap() on Solaris or *BSD */\n\tobj->phdr = NULL;\n\tobj->name = soname;\n\tdl_iterate_phdr(eh_find_callback, obj);\n\n\tif (!obj->phdr)\n\t\treturn EAGAIN;\n\n\treturn eh_init_obj(obj);\n}\n\nint eh_check_addr(eh_obj_t *obj, const void *addr)\n{\n\t/*\n\t Check that given address is inside program's\n\t memory maps. PT_LOAD program headers tell us\n\t where program has been loaded into.\n\t*/\n\tint p;\n\tfor (p = 0; p < obj->phnum; p++) {\n\t\tif (obj->phdr[p].p_type == PT_LOAD) {\n\t\t\tif (((ElfW(Addr)) addr < obj->phdr[p].p_memsz + obj->phdr[p].p_vaddr + obj->addr) &&\n\t\t\t    ((ElfW(Addr)) addr >= obj->phdr[p].p_vaddr + obj->addr))\n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn EINVAL;\n}\n\nint eh_init_obj(eh_obj_t *obj)\n{\n\t/*\n\t ELF spec says in section header documentation, that:\n\t \"An object file may have only one dynamic section.\"\n\n\t Let's assume it means that object has only one PT_DYNAMIC\n\t as well.\n\t*/\n\tint p;\n\tobj->dynamic = NULL;\n\tfor (p = 0; p < obj->phnum; p++) {\n\t\tif (obj->phdr[p].p_type == PT_DYNAMIC) {\n\t\t\tif (obj->dynamic)\n\t\t\t\treturn ENOTSUP;\n\n\t\t\tobj->dynamic = (ElfW(Dyn) *) (obj->phdr[p].p_vaddr + obj->addr);\n\t\t}\n\t}\n\n\tif (!obj->dynamic)\n\t\treturn ENOTSUP;\n\n\t/*\n\t ELF spec says that program is allowed to have more than one\n\t .strtab but does not describe how string table indexes translate\n\t to multiple string tables.\n\n\t And spec says that only one SHT_HASH is allowed, does it mean that\n\t obj has only one DT_HASH?\n\n\t About .symtab it does not mention anything about if multiple\n\t symbol tables are allowed or not.\n\n\t Maybe st_shndx is the key here?\n\t*/\n\tobj->strtab = NULL;\n\tobj->hash = NULL;\n\tobj->gnu_hash = NULL;\n\tobj->symtab = NULL;\n\tp = 0;\n\twhile (obj->dynamic[p].d_tag != DT_NULL) {\n\t\tif (obj->dynamic[p].d_tag == DT_STRTAB) {\n\t\t\tif (obj->strtab)\n\t\t\t\treturn ENOTSUP;\n\n\t\t\tobj->strtab = (const char *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\t\t} else if (obj->dynamic[p].d_tag == DT_HASH) {\n\t\t\tif (obj->hash)\n\t\t\t\treturn ENOTSUP;\n\n\t\t\tobj->hash = (ElfW(Word) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\t\t} else if (obj->dynamic[p].d_tag == DT_GNU_HASH) {\n\t\t\tif (obj->gnu_hash)\n\t\t\t\treturn ENOTSUP;\n\n\t\t\tobj->gnu_hash = (Elf32_Word *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\t\t} else if (obj->dynamic[p].d_tag == DT_SYMTAB) {\n\t\t\tif (obj->symtab)\n\t\t\t\treturn ENOTSUP;\n\n\t\t\tobj->symtab = (ElfW(Sym) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\t\t}\n\t\tp++;\n\t}\n\n\t/* This is here to catch b0rken headers (vdso) */\n\tif ((eh_check_addr(obj, (const void *) obj->strtab)) |\n\t    (eh_check_addr(obj, (const void *) obj->symtab)))\n\t\treturn ENOTSUP;\n\n\tif (obj->hash) {\n\t\t/* DT_HASH found */\n\t\tif (eh_check_addr(obj, (void *) obj->hash))\n\t\t\tobj->hash = NULL;\n\t} else if (obj->gnu_hash) {\n\t\t/* DT_GNU_HASH found */\n\t\tif (eh_check_addr(obj, (void *) obj->gnu_hash))\n\t\t\tobj->gnu_hash = NULL;\n\t}\n\n\treturn 0;\n}\n\nint eh_find_sym(eh_obj_t *obj, const char *name, void **to)\n{\n\teh_sym_t sym;\n\n\t/* DT_GNU_HASH is faster ;) */\n\tif (obj->gnu_hash) {\n\t\tif (!eh_find_sym_gnu_hash(obj, name, &sym)) {\n\t\t\t*to = (void *) (sym.sym->st_value + obj->addr);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/* maybe it is in DT_HASH or DT_GNU_HASH is not present */\n\tif (obj->hash) {\n\t\tif (!eh_find_sym_hash(obj, name, &sym)) {\n\t\t\t*to = (void *) (sym.sym->st_value + obj->addr);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn EAGAIN;\n}\n\nElfW(Word) eh_hash_elf(const char *name)\n{\n\tElfW(Word) tmp, hash = 0;\n\tconst unsigned char *uname = (const unsigned char *) name;\n\tint c;\n\n\twhile ((c = *uname++) != '\\0') {\n\t\thash = (hash << 4) + c;\n\t\tif ((tmp = (hash & 0xf0000000)) != 0) {\n\t\t\thash ^= tmp >> 24;\n\t\t\thash ^= tmp;\n\t\t}\n\t}\n\n\treturn hash;\n}\n\nint eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym)\n{\n\tElfW(Word) hash, *chain;\n\tElfW(Sym) *esym;\n\tunsigned int bucket_idx, idx;\n\n\tif (!obj->hash)\n\t\treturn ENOTSUP;\n\n\tif (obj->hash[0] == 0)\n\t\treturn EAGAIN;\n\n\thash = eh_hash_elf(name);\n\t/*\n\t First item in DT_HASH is nbucket, second is nchain.\n\t hash % nbucket gives us our bucket index.\n\t*/\n\tbucket_idx = obj->hash[2 + (hash % obj->hash[0])];\n\tchain = &obj->hash[2 + obj->hash[0] + bucket_idx];\n\n\tidx = 0;\n\tsym->sym = NULL;\n\n\t/* we have to check symtab[bucket_idx] first */\n\tesym = &obj->symtab[bucket_idx];\n\tif (esym->st_name) {\n\t\tif (!strcmp(&obj->strtab[esym->st_name], name))\n\t\t\tsym->sym = esym;\n\t}\n\n\twhile ((sym->sym == NULL) &&\n\t       (chain[idx] != STN_UNDEF)) {\n\t\tesym = &obj->symtab[chain[idx]];\n\n\t\tif (esym->st_name) {\n\t\t\tif (!strcmp(&obj->strtab[esym->st_name], name))\n\t\t\t\tsym->sym = esym;\n\t\t}\n\n\t\tidx++;\n\t}\n\n\t/* symbol not found */\n\tif (sym->sym == NULL)\n\t\treturn EAGAIN;\n\n\tsym->obj = obj;\n\tsym->name = &obj->strtab[sym->sym->st_name];\n\n\treturn 0;\n}\n\nElf32_Word eh_hash_gnu(const char *name)\n{\n\tElf32_Word hash = 5381;\n\tconst unsigned char *uname = (const unsigned char *) name;\n\tint c;\n\n\twhile ((c = *uname++) != '\\0')\n\t\thash = (hash << 5) + hash + c;\n\n\treturn hash & 0xffffffff;\n}\n\nint eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym)\n{\n\tElf32_Word *buckets, *chain_zero, *hasharr;\n\tElfW(Addr) *bitmask, bitmask_word;\n\tElf32_Word symbias, bitmask_nwords, bucket,\n\t\t   nbuckets, bitmask_idxbits, shift;\n\tElf32_Word hash, hashbit1, hashbit2;\n\tElfW(Sym) *esym;\n\n\tif (!obj->gnu_hash)\n\t\treturn ENOTSUP;\n\n\tif (obj->gnu_hash[0] == 0)\n\t\treturn EAGAIN;\n\n\tsym->sym = NULL;\n\n\t/*\n\t Initialize our hash table stuff\n\n\t DT_GNU_HASH is(?):\n\t [nbuckets] [symbias] [bitmask_nwords] [shift]\n\t [bitmask_nwords * ElfW(Addr)] <- bitmask\n\t [nbuckets * Elf32_Word] <- buckets\n\t ...chains? - symbias...\n\t */\n\tnbuckets = obj->gnu_hash[0];\n\tsymbias = obj->gnu_hash[1];\n\tbitmask_nwords = obj->gnu_hash[2]; /* must be power of two */\n\tbitmask_idxbits = bitmask_nwords - 1;\n\tshift = obj->gnu_hash[3];\n\tbitmask = (ElfW(Addr) *) &obj->gnu_hash[4];\n\tbuckets = &obj->gnu_hash[4 + (__ELF_NATIVE_CLASS / 32) * bitmask_nwords];\n\tchain_zero = &buckets[nbuckets] - symbias;\n\n\t/* hash our symbol */\n\thash = eh_hash_gnu(name);\n\n\t/* bitmask stuff... no idea really :D */\n\tbitmask_word = bitmask[(hash / __ELF_NATIVE_CLASS) & bitmask_idxbits];\n\thashbit1 = hash & (__ELF_NATIVE_CLASS - 1);\n\thashbit2 = (hash >> shift) & (__ELF_NATIVE_CLASS - 1);\n\n\t/* wtf this does actually? */\n\tif (!((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1))\n\t\treturn EAGAIN;\n\n\t/* locate bucket */\n\tbucket = buckets[hash % nbuckets];\n\tif (bucket == 0)\n\t\treturn EAGAIN;\n\n\t/* and find match in chain */\n\thasharr = &chain_zero[bucket];\n\tdo {\n\t\tif (((*hasharr ^ hash) >> 1) == 0) {\n\t\t\t/* hash matches, but does the name? */\n\t\t\tesym = &obj->symtab[hasharr - chain_zero];\n\t\t\tif (esym->st_name) {\n\t\t\t\tif (!strcmp(&obj->strtab[esym->st_name], name)) {\n\t\t\t\t\tsym->sym = esym;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} while ((*hasharr++ & 1u) == 0);\n\n\t/* symbol not found */\n\tif (sym->sym == NULL)\n\t\treturn EAGAIN;\n\n\tsym->obj = obj;\n\tsym->name = &obj->strtab[sym->sym->st_name];\n\n\treturn 0;\n}\n\nint eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg)\n{\n\treturn ENOTSUP;\n}\n\nint eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next)\n{\n\t/* first from i + 1 to end, then from start to i - 1 */\n\tint p;\n\t*next = NULL;\n\n\tp = i + 1;\n\twhile (obj->dynamic[p].d_tag != DT_NULL) {\n\t\tif (obj->dynamic[p].d_tag == tag) {\n\t\t\t*next = &obj->dynamic[p];\n\t\t\treturn 0;\n\t\t}\n\t\tp++;\n\t}\n\n\tp = 0;\n\twhile ((obj->dynamic[i].d_tag != DT_NULL) && (p < i)) {\n\t\tif (obj->dynamic[p].d_tag == tag) {\n\t\t\t*next = &obj->dynamic[p];\n\t\t\treturn 0;\n\t\t}\n\t\tp++;\n\t}\n\n\treturn EAGAIN;\n}\n\nint eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val)\n{\n\tElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\tElfW(Dyn) *relasize;\n\tunsigned int i;\n\n\t/* DT_PLTRELSZ contains PLT relocs size in bytes */\n\tif (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize))\n\t\treturn EINVAL; /* b0rken elf :/ */\n\n\tfor (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) {\n\t\tif (!obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name)\n\t\t\tcontinue;\n\n\t\tif (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name], sym))\n\t\t\t*((void **) (rela[i].r_offset + obj->addr)) = val;\n\t}\n\n\treturn 0;\n}\n\nint eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val)\n{\n\tElfW(Rel) *rel = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\tElfW(Dyn) *relsize;\n\tunsigned int i;\n\n\tif (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize))\n\t\treturn EINVAL; /* b0rken elf :/ */\n\n\tfor (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) {\n\t\tif (!obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name)\n\t\t\tcontinue;\n\n\t\tif (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name], sym))\n\t\t\t*((void **) (rel[i].r_offset + obj->addr)) = val;\n\t}\n\n\treturn 0;\n}\n\nint eh_set_rel(eh_obj_t *obj, const char *sym, void *val)\n{\n\t/*\n\t Elf spec states that object is allowed to have multiple\n\t .rel.plt and .rela.plt tables, so we will support 'em - here.\n\t*/\n\tElfW(Dyn) *pltrel;\n\tint ret, p = 0;\n\n\twhile (obj->dynamic[p].d_tag != DT_NULL) {\n\t\t/* DT_JMPREL contains .rel.plt or .rela.plt */\n\t\tif (obj->dynamic[p].d_tag == DT_JMPREL) {\n\t\t\t/* DT_PLTREL tells if it is Rela or Rel */\n\t\t\teh_find_next_dyn(obj, DT_PLTREL, p, &pltrel);\n\n\t\t\tif (pltrel->d_un.d_val == DT_RELA) {\n\t\t\t\tif ((ret = eh_set_rela_plt(obj, p, sym, val)))\n\t\t\t\t\treturn ret;\n\t\t\t} else if (pltrel->d_un.d_val == DT_REL) {\n\t\t\t\tif ((ret = eh_set_rel_plt(obj, p, sym, val)))\n\t\t\t\t\treturn ret;\n\t\t\t} else\n\t\t\t\treturn EINVAL;\n\t\t}\n\t\tp++;\n\t}\n\n\treturn 0;\n}\n\nint eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)\n{\n\tElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\tElfW(Dyn) *relasize;\n\teh_rel_t rel;\n\teh_sym_t sym;\n\tunsigned int i, ret;\n\n\trel.sym = &sym;\n\trel.rel = NULL;\n\trel.obj = obj;\n\n\tif (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize))\n\t\treturn EINVAL;\n\n\tfor (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) {\n\t\trel.rela = &rela[i];\n\t\tsym.sym = &obj->symtab[ELFW_R_SYM(rel.rela->r_info)];\n\t\tif (sym.sym->st_name)\n\t\t\tsym.name = &obj->strtab[sym.sym->st_name];\n\t\telse\n\t\t\tsym.name = NULL;\n\n\t\tif ((ret = callback(&rel, arg)))\n\t\t\treturn ret;\n\t}\n\n\treturn 0;\n}\n\nint eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg)\n{\n\tElfW(Rel) *relp = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr);\n\tElfW(Dyn) *relsize;\n\teh_rel_t rel;\n\teh_sym_t sym;\n\tunsigned int i, ret;\n\n\trel.sym = &sym;\n\trel.rela = NULL;\n\trel.obj = obj;\n\n\tif (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize))\n\t\treturn EINVAL;\n\n\tfor (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) {\n\t\trel.rel = &relp[i];\n\t\tsym.sym = &obj->symtab[ELFW_R_SYM(rel.rel->r_info)];\n\t\tif (sym.sym->st_name)\n\t\t\tsym.name = &obj->strtab[sym.sym->st_name];\n\t\telse\n\t\t\tsym.name = NULL;\n\n\t\tif ((ret = callback(&rel, arg)))\n\t\t\treturn ret;\n\t}\n\n\treturn 0;\n}\n\nint eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg)\n{\n\tElfW(Dyn) *pltrel;\n\tint ret, p = 0;\n\n\twhile (obj->dynamic[p].d_tag != DT_NULL) {\n\t\tif (obj->dynamic[p].d_tag == DT_JMPREL) {\n\t\t\teh_find_next_dyn(obj, DT_PLTREL, p, &pltrel);\n\n\t\t\tif (pltrel->d_un.d_val == DT_RELA) {\n\t\t\t\tif ((ret = eh_iterate_rela_plt(obj, p, callback, arg)))\n\t\t\t\t\treturn ret;\n\t\t\t} else if (pltrel->d_un.d_val == DT_REL) {\n\t\t\t\tif ((ret = eh_iterate_rel_plt(obj, p, callback, arg)))\n\t\t\t\t\treturn ret;\n\t\t\t} else\n\t\t\t\treturn EINVAL;\n\t\t}\n\t\tp++;\n\t}\n\n\treturn 0;\n}\n\nint eh_destroy_obj(eh_obj_t *obj)\n{\n\tobj->phdr = NULL;\n\n\treturn 0;\n}\n\n/**  \\} */\n"
  },
  {
    "path": "src/fcat.h",
    "content": "#pragma once\n#ifndef MANGOHUD_FCAT_H\n#define MANGOHUD_FCAT_H\n\n#include <iostream>\n#include <vector>\n#include <fstream>\n#include <chrono>\n#include <thread>\n#include <condition_variable>\n#include <array>\n\n#include \"timing.hpp\"\n\n#include \"overlay_params.h\"\n#include \"overlay.h\"\n\nstruct fcatoverlay{\n  const struct overlay_params* params = nullptr;\n  const std::array<const ImColor,16> sequence={{{255, 255, 255},{0, 255, 0},{0, 0, 255},{255, 0, 0},{0, 128, 128},{0, 0, 128},{0, 128, 0},{0, 255, 255},{128, 0, 0},{192, 192, 192},{128, 0, 128},{128, 128, 0},{128, 128, 128},{255, 0, 255},{255, 255, 0},{255, 128, 0}}};\n  void update(const struct overlay_params* params_){\n    params=params_;\n  };\n  ImColor get_next_color (const swapchain_stats& sw_stats){\n    size_t currentColor = sw_stats.n_frames % 16;// should probably be sequence.size(); but this doesn't matter as all FCAT analysis tools use this exact 16 colour sequence.\n    ImColor output = sequence[currentColor];\n    return output;\n  };\n  std::array<ImVec2,3> get_overlay_corners()\n  {\n    unsigned short screen_edge=params->fcat_screen_edge;\n    auto window_size = ImVec2(params->fcat_overlay_width,ImGui::GetIO().DisplaySize.y);\n    auto p_min = ImVec2(0.,0.);\n    auto p_max = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y);\n    //Switch the used screen edge, this enables capture from devices with any screen orientation.\n    //This goes counter-clockwise from the left edge (0)\n    switch (screen_edge)\n      {\n      default:\n      case 0:\n\tbreak;\n      case 1:\n\twindow_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x);\n\tp_min = ImVec2(0,ImGui::GetIO().DisplaySize.y - window_size.y);\n\tp_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y);\n\tbreak;\n      case 2:\n\twindow_size = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y);\n\tp_min = ImVec2(ImGui::GetIO().DisplaySize.x-window_size.x,0);\n\tp_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y);\n\tbreak;\n      case 3:\n\twindow_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x);\n\tp_min = ImVec2(0,0);\n\tp_max = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.y);\n\tbreak;\n         }\n    std::array<ImVec2,3> output={{p_min,p_max,window_size}};\n    return output;\n  };\n};\n\n#endif\n"
  },
  {
    "path": "src/fex.cpp",
    "content": "#include <spdlog/spdlog.h>\n#include <map>\n#include <string>\n#include <unistd.h>\n#include <sys/mman.h>\n\n#include \"fex.h\"\n#include \"hud_elements.h\"\n#include \"mesa/util/macros.h\"\n#if defined(__x86_64__) || defined(__i386__)\n#include <immintrin.h>\n#endif\n\nconstexpr uint64_t AlignUp(uint64_t Value, uint64_t Alignment) {\n    return Value + (Alignment - Value % Alignment) % Alignment;\n}\n\nnamespace fex {\nconst char* fex_status = \"Not Found!\";\nstd::string fex_version;\nstd::vector<float> fex_load_data(200,0.f);\n\nfex_event_counts sigbus_counts;\nfex_event_counts smc_counts;\nfex_event_counts softfloat_counts;\n\nstd::vector<float> fex_max_thread_loads;\n\nconstexpr static uint32_t MAXIMUM_THREAD_WAIT_TIME = 10;\n\n// FEX-Emu stats definitions\n// Semantically these match upstream FEX-Emu.\nconstexpr uint32_t FEX_STATS_VERSION = 2;\nenum class AppType : uint8_t {\n    LINUX_32,\n    LINUX_64,\n    WIN_ARM64EC,\n    WIN_WOW64,\n};\n\n// The profile statistics header that is at the base of the shared memory mapped from FEX.\n// The version member is guaranteed to be first, to ensure that any version changes can be picked up immediately.\nstruct fex_stats_header {\n    uint8_t Version;\n    AppType app_type;\n    uint16_t thread_stats_size;\n    char fex_version[48];\n    // Atomic variables. std::atomic_ref isn't available until C++20, so need to use GCC builtin atomics to access.\n    uint32_t Head;\n    uint32_t Size;\n    uint32_t Pad;\n};\n\n// The thread-specific datapoints. If TID is zero then it is deallocated and happens to still be in the linked list.\nstruct fex_thread_stats {\n    // Atomic variables.\n    uint32_t Next;\n    uint32_t TID;\n    // Thread-specific stats.\n    uint64_t AccumulatedJITTime;\n    uint64_t AccumulatedSignalTime;\n    uint64_t AccumulatedSIGBUSCount;\n    uint64_t AccumulatedSMCEvents;\n    uint64_t AccumulatedFloatFallbackCount;\n};\n\n// This is guaranteed by FEX.\nstatic_assert(sizeof(fex_thread_stats) % 16 == 0, \"\");\n\n// Sampled stats information\nstruct fex_stats {\n    int pid {-1};\n    int shm_fd {-1};\n    bool first_sample = true;\n    uint32_t shm_size{};\n    uint64_t cycle_counter_frequency{};\n    size_t hardware_concurrency{};\n    size_t page_size{};\n\n    void* shm_base{};\n    size_t fex_thread_stats_size {};\n    fex_stats_header* head{};\n    fex_thread_stats* stats{};\n\n    struct retained_stats {\n        std::chrono::time_point<std::chrono::steady_clock> last_seen{};\n        fex_thread_stats previous{};\n        fex_thread_stats current{};\n    };\n    std::chrono::time_point<std::chrono::steady_clock> previous_sample_period;\n    std::map<int, retained_stats> sampled_stats;\n};\n\nfex_stats g_stats {};\n\nconst char* get_fex_app_type() {\n    if (!g_stats.head) {\n        return \"Unknown\";\n    }\n\n    // These are the only application types that FEX-Emu supports today.\n    // Linux32: A 32-bit x86 Linux application\n    // Linux64: A 64-bit x86_64 Linux application\n    // arm64ec: A 64-bit x86_64 WINE application\n    //   wow64: A 32-bit x86 WINE application\n    switch (g_stats.head->app_type) {\n        case AppType::LINUX_32: return \"Linux32\";\n        case AppType::LINUX_64: return \"Linux64\";\n        case AppType::WIN_ARM64EC: return \"arm64ec\";\n        case AppType::WIN_WOW64: return \"wow64\";\n        default: return \"Unknown\";\n    }\n}\n\nstatic fex_thread_stats *offset_to_stats(void* shm_base, uint32_t *offset) {\n    const auto ld = __atomic_load_n(offset, __ATOMIC_RELAXED);\n    if (ld == 0) return nullptr;\n    return reinterpret_cast<fex_thread_stats*>(reinterpret_cast<uint64_t>(shm_base) + ld);\n}\n\nstatic fex_thread_stats *offset_to_stats(void* shm_base, uint32_t offset) {\n    if (offset == 0) return nullptr;\n    return reinterpret_cast<fex_thread_stats*>(reinterpret_cast<uint64_t>(shm_base) + offset);\n}\n\n#ifdef __aarch64__\nstatic void memory_barrier() {\n    asm volatile(\"dmb ishst\" ::: \"memory\");\n}\nstatic uint64_t get_cycle_counter_frequency() {\n    uint64_t result;\n    asm (\"mrs %[res], CNTFRQ_EL0;\"\n        : [res] \"=r\" (result));\n    return result;\n}\nbool is_fex_capable() {\n    // All aarch64 systems are fex capable.\n    return true;\n}\n\n#elif defined(__x86_64__) || defined(__i386__)\nstatic void memory_barrier() {\n    // Intentionally empty.\n}\nstatic void cpuid(uint32_t leaf, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx) {\n    asm volatile(\"cpuid\"\n            : \"=a\"(eax), \"=b\"(ebx), \"=c\"(ecx), \"=d\"(edx)\n            : \"a\"(leaf), \"c\"(0));\n}\n\nbool is_fex_capable() {\n    // FEX-Emu CPUID documentation: https://github.com/FEX-Emu/FEX/blob/main/docs/CPUID.md\n    const uint32_t HYPERVISOR_BIT = 1U << 31;\n    const char FEXHypervisorString[] = \"FEXIFEXIEMU\";\n    char HypervisorString[4 * 3];\n\n    uint32_t eax, ebx, ecx, edx;\n    // Check that the hypervisor bit is set first. Not required, but good to do.\n    cpuid(1, eax, ebx, ecx, edx);\n    if ((ecx & HYPERVISOR_BIT) != HYPERVISOR_BIT) return false;\n\n    // Once the hypervisor bit is set, query the hypervisor leaf.\n    cpuid(0x4000'0000U, eax, ebx, ecx, edx);\n    if (eax == 0) return false;\n\n    // If the hypervisor description matches FEX then we're good.\n    memcpy(&HypervisorString[0], &ebx, sizeof(uint32_t));\n    memcpy(&HypervisorString[4], &ecx, sizeof(uint32_t));\n    memcpy(&HypervisorString[8], &edx, sizeof(uint32_t));\n    if (strncmp(HypervisorString, FEXHypervisorString, sizeof(HypervisorString)) != 0) return false;\n\n    return true;\n}\n\nstatic uint64_t get_cycle_counter_frequency() {\n    // In a FEX-Emu environment, the cycle counter frequency is exposed in CPUID leaf 0x15.\n    // This matches x86 Intel semantics on latest CPUs, see their documentation for the exact implementation details.\n    uint32_t eax, ebx, ecx, edx;\n    cpuid(0, eax, ebx, ecx, edx);\n    if (eax < 0x15) return 0;\n\n    cpuid(0x15U, eax, ebx, ecx, edx);\n\n    // Ignore scale in ebx\n    // Baseline clock is provided in ecx.\n    return ecx;\n}\n#endif\n\nstatic void atomic_copy_thread_stats(fex_thread_stats *dest, const fex_thread_stats *src) {\n#if defined(__x86_64__) || defined(__i386__)\n    // For x86 platforms, XMM copies are atomic when aligned. So this guarantees single-copy atomicity.\n    // x86 has no equivalent of an true \"atomic\" 128-bit GPR loadstore until APX.\n    // For FEX emulating x86 platforms, this is also a guarantee for ARMv8.4 and newer.\n    using copy_type = __m128;\n#else\n    // For ARM64 platforms this is basically guaranteed to turn in to ldp+stp.\n    // For ARM8.4 this gives us single-copy atomicity guarantees.\n    using copy_type = __uint128_t;\n#endif\n\n    const auto elements_to_copy = g_stats.fex_thread_stats_size / sizeof(copy_type);\n    auto d_i = reinterpret_cast<copy_type*>(dest);\n    auto s_i = reinterpret_cast<const copy_type*>(src);\n    for (size_t i = 0; i < elements_to_copy; ++i) {\n        d_i[i] = s_i[i];\n    }\n}\n\nstatic void destroy_shm() {\n    munmap(g_stats.shm_base, g_stats.shm_size);\n    close(g_stats.shm_fd);\n    g_stats.shm_fd = -1;\n    g_stats.shm_size = 0;\n    g_stats.shm_base = nullptr;\n    g_stats.head = nullptr;\n    g_stats.stats = nullptr;\n    g_stats.sampled_stats.clear();\n}\n\nstatic void init_shm(int pid) {\n    // Initialize global hardware stats.\n    g_stats.cycle_counter_frequency = get_cycle_counter_frequency();\n    g_stats.hardware_concurrency = std::thread::hardware_concurrency();\n    g_stats.page_size = sysconf(_SC_PAGESIZE);\n    if (g_stats.page_size <= 0) g_stats.page_size = 4096;\n\n    // Try and open a FEX stats file that relates to the PID in focus.\n    // If this fails then it is non-fatal, just means FEX isn't creating stats for that process.\n    std::string f = \"fex-\";\n    f += std::to_string(pid);\n    f += \"-stats\";\n    int fd {-1};\n    struct stat buf{};\n    uint64_t shm_size{};\n    void* shm_base{MAP_FAILED};\n    fex_stats_header *header{};\n\n    fd = shm_open(f.c_str(), O_RDONLY, 0);\n    if (fd == -1) {\n        goto err;\n    }\n\n    if (fstat(fd, &buf) == -1) {\n        goto err;\n    }\n\n    if (buf.st_size < static_cast<off_t>(sizeof(fex_stats_header))) {\n        goto err;\n    }\n\n    shm_size = AlignUp(buf.st_size, g_stats.page_size);\n\n    shm_base = mmap(nullptr, shm_size, PROT_READ, MAP_SHARED, fd, 0);\n    if (shm_base == MAP_FAILED) {\n        goto err;\n    }\n\n    memory_barrier();\n    header = reinterpret_cast<fex_stats_header*>(shm_base);\n    if (header->Version != FEX_STATS_VERSION) {\n        // If the version read doesn't match the implementation then we can't read.\n        fex_status = \"version mismatch\";\n        goto err;\n    }\n\n    if (g_stats.shm_fd != -1) {\n        // Destroy first if the FD changed.\n        destroy_shm();\n    }\n\n    // Cache off the information, we have successfully loaded the stats SHM.\n    g_stats.pid = pid;\n    g_stats.shm_fd = fd;\n    g_stats.shm_size = shm_size;\n    g_stats.shm_base = shm_base;\n    g_stats.head = header;\n    g_stats.stats = offset_to_stats(shm_base, &header->Head);\n    g_stats.previous_sample_period = std::chrono::steady_clock::now();\n    g_stats.first_sample = true;\n    g_stats.sampled_stats.clear();\n\n    g_stats.fex_thread_stats_size = sizeof(fex_thread_stats);\n\n    if (g_stats.head->thread_stats_size) {\n        // If thread stats size is provided, use that, as long as it is smaller than tracking size.\n        g_stats.fex_thread_stats_size = std::min<size_t>(g_stats.head->thread_stats_size, g_stats.fex_thread_stats_size);\n    }\n\n    fex_version = std::string {header->fex_version, strnlen(header->fex_version, sizeof(header->fex_version))};\n    sigbus_counts.account_time(g_stats.previous_sample_period);\n    smc_counts.account_time(g_stats.previous_sample_period);\n    softfloat_counts.account_time(g_stats.previous_sample_period);\n    std::fill(fex_load_data.begin(), fex_load_data.end(), 0.0);\n    fex_max_thread_loads.clear();\n    return;\nerr:\n    if (fd != -1) {\n        close(fd);\n    }\n\n    if (shm_base != MAP_FAILED) {\n        munmap(shm_base, shm_size);\n    }\n}\n\nstatic void check_shm_update_necessary() {\n    // If the SHM has changed size then we need to unmap and remap with the new size.\n    // Required since FEX may grow the SHM region to fit more threads, although previous thread data won't be invalidated.\n    memory_barrier();\n    auto new_shm_size = AlignUp(__atomic_load_n(&g_stats.head->Size, __ATOMIC_RELAXED), g_stats.page_size);\n    if (g_stats.shm_size == new_shm_size) {\n        return;\n    }\n\n    munmap(g_stats.shm_base, g_stats.shm_size);\n    g_stats.shm_size = new_shm_size;\n    g_stats.shm_base = mmap(nullptr, new_shm_size, PROT_READ, MAP_SHARED, g_stats.shm_fd, 0);\n    g_stats.head = reinterpret_cast<fex_stats_header*>(g_stats.shm_base);\n    g_stats.stats = offset_to_stats(g_stats.shm_base, &g_stats.head->Head);\n    g_stats.fex_thread_stats_size = sizeof(fex_thread_stats);\n\n    if (g_stats.head->thread_stats_size) {\n        // If thread stats size is provided, use that, as long as it is smaller than tracking size.\n        g_stats.fex_thread_stats_size = std::min<size_t>(g_stats.head->thread_stats_size, g_stats.fex_thread_stats_size);\n    }\n}\n\nbool is_fex_pid_found() {\n    return g_stats.pid != -1;\n}\n\nvoid update_fex_stats() {\n    auto gs_pid = HUDElements.g_gamescopePid > 0 ? HUDElements.g_gamescopePid : ::getpid();\n    if (gs_pid < 1) {\n        // No PID yet.\n        return;\n    }\n\n    if (g_stats.pid != gs_pid) {\n        // PID changed, likely gamescope changed focus.\n        init_shm(gs_pid);\n    }\n\n    if (g_stats.pid == -1) {\n        // PID became invalid. Likely due to error reading SHM.\n        return;\n    }\n\n    // Check if SHM changed first.\n    check_shm_update_necessary();\n\n    // Before reading stats, a memory barrier needs to be done.\n    // This ensures visibility of the stats before reading, as they use weak atomics for writes.\n    memory_barrier();\n\n    // Sample the stats and store them off.\n    // Sampling these quickly lets us become a loose sampling profiler, since FEX updates these constantly.\n    uint32_t *header_offset_atomic = &g_stats.head->Head;\n    auto now = std::chrono::steady_clock::now();\n    for (auto header_offset = __atomic_load_n(header_offset_atomic, __ATOMIC_RELAXED);\n         header_offset != 0;\n         header_offset = __atomic_load_n(header_offset_atomic, __ATOMIC_RELAXED)) {\n        if (header_offset >= g_stats.shm_size) break;\n\n        fex_thread_stats *stat = offset_to_stats(g_stats.shm_base, header_offset);\n        const auto TID = __atomic_load_n(&stat->TID, __ATOMIC_RELAXED);\n        if (TID != 0) {\n            fex_stats::retained_stats &sampled_stats = g_stats.sampled_stats[TID];\n            atomic_copy_thread_stats(&sampled_stats.current, stat);\n            sampled_stats.last_seen = now;\n        }\n\n        header_offset_atomic = &stat->Next;\n    }\n\n    if (g_stats.first_sample) {\n        // Skip first sample, it'll look crazy.\n        g_stats.first_sample = false;\n        fex_status = \"Accumulating\";\n        return;\n    }\n\n    // Update the status with the FEX version.\n    fex_status = fex_version.c_str();\n\n    // Accumulate full JIT time\n    uint64_t total_jit_time{};\n    uint64_t total_sigbus_events{};\n    uint64_t total_smc_events{};\n    uint64_t total_softfloat_events{};\n    size_t threads_sampled{};\n#define accumulate(dest, name) dest += it->second.current.name - it->second.previous.name\n    std::vector<uint64_t> hottest_threads{};\n    for (auto it = g_stats.sampled_stats.begin(); it != g_stats.sampled_stats.end();) {\n        ++threads_sampled;\n        uint64_t total_time{};\n        accumulate(total_time, AccumulatedJITTime);\n        accumulate(total_time, AccumulatedSignalTime);\n        accumulate(total_sigbus_events, AccumulatedSIGBUSCount);\n        accumulate(total_smc_events, AccumulatedSMCEvents);\n        accumulate(total_softfloat_events, AccumulatedFloatFallbackCount);\n\n        memcpy(&it->second.previous, &it->second.current, g_stats.fex_thread_stats_size);\n\n        total_jit_time += total_time;\n        if ((now - it->second.last_seen) >= std::chrono::seconds(MAXIMUM_THREAD_WAIT_TIME)) {\n            it = g_stats.sampled_stats.erase(it);\n            continue;\n        }\n        hottest_threads.emplace_back(total_time);\n        ++it;\n    }\n\n    std::sort(hottest_threads.begin(), hottest_threads.end(), std::greater<uint64_t>());\n\n    // Calculate loads based on the sample period that occurred.\n    // FEX-Emu only counts cycles for the amount of time, so we need to calculate load based on the number of cycles that the sample period has.\n    const auto sample_period = now - g_stats.previous_sample_period;\n\n    const double NanosecondsInSeconds = 1'000'000'000.0;\n    const double SamplePeriodNanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(sample_period).count();\n    const double MaximumCyclesInSecond = (double)g_stats.cycle_counter_frequency;\n    const double MaximumCyclesInSamplePeriod = MaximumCyclesInSecond * (SamplePeriodNanoseconds / NanosecondsInSeconds);\n    const double MaximumCoresThreadsPossible = std::min(g_stats.hardware_concurrency, threads_sampled);\n\n    // Calculate the percentage of JIT time that could possibly exist inside the sample period.\n    double fex_load = ((double)total_jit_time / (MaximumCyclesInSamplePeriod * MaximumCoresThreadsPossible)) * 100.0;\n    size_t minimum_hot_threads = std::min(g_stats.hardware_concurrency, hottest_threads.size());\n    // For the top thread-loads, we are only ever showing up to how many hardware threads are available.\n    fex_max_thread_loads.resize(minimum_hot_threads);\n    for (size_t i = 0; i < minimum_hot_threads; ++i) {\n       fex_max_thread_loads[i] = ((double)hottest_threads[i] / MaximumCyclesInSamplePeriod) * 100.0;\n    }\n\n    sigbus_counts.account(total_sigbus_events, now);\n    smc_counts.account(total_smc_events, now);\n    softfloat_counts.account(total_softfloat_events, now);\n\n    g_stats.previous_sample_period = now;\n\n    fex_load_data.push_back(fex_load);\n    fex_load_data.erase(fex_load_data.begin());\n}\n}\n"
  },
  {
    "path": "src/fex.h",
    "content": "#pragma once\n#ifdef HAVE_FEX\n#ifndef MANGOHUD_FEX_H\n#define MANGOHUD_FEX_H\n#include <cstdint>\n#include <vector>\n#include <string>\n\nnamespace fex {\nbool is_fex_capable();\nbool is_fex_pid_found();\nconst char* get_fex_app_type();\n\nextern const char* fex_status;\nextern std::string fex_version;\n\nextern std::vector<float> fex_load_data;\n\nstruct fex_event_counts {\n    public:\n        void account(uint64_t total, std::chrono::time_point<std::chrono::steady_clock> now) {\n            count = total;\n            last_sample_count += total;\n\n            const auto diff = now - last_chrono;\n            if (diff >= std::chrono::seconds(1)) {\n                // Calculate the average over the last second.\n                const double NanosecondsInSeconds = 1'000'000'000.0;\n                const auto diff_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();\n                const double Percentage = (double)diff_ns / NanosecondsInSeconds;\n                average_sec = double(last_sample_count) * Percentage;\n                last_sample_count = 0;\n                last_chrono = now;\n            }\n        }\n\n        void account_time(std::chrono::time_point<std::chrono::steady_clock> now) {\n            last_chrono = now;\n        }\n        uint64_t Count() const { return count; }\n        double Avg() const { return average_sec; }\n    private:\n        uint64_t count{};\n        uint64_t last_sample_count{};\n        double average_sec{};\n        std::chrono::time_point<std::chrono::steady_clock> last_chrono{};\n};\nextern fex_event_counts sigbus_counts;\nextern fex_event_counts smc_counts;\nextern fex_event_counts softfloat_counts;\n\nextern std::vector<float> fex_max_thread_loads;\nvoid update_fex_stats();\n}\n\n#endif //MANGOHUD_FEX_H\n#endif //HAVE_FEX\n"
  },
  {
    "path": "src/file_utils.cpp",
    "content": "#include \"file_utils.h\"\n#include \"string_utils.h\"\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <dirent.h>\n#include <limits.h>\n#include <fstream>\n#include <cstring>\n#include <string>\n#include <spdlog/spdlog.h>\n\n#ifndef PROCDIR\n#define PROCDIR \"/proc\"\n#endif\n\nstd::string read_line(const std::string& filename)\n{\n    std::string line;\n    std::ifstream file(filename);\n    if (file.fail()){\n        return line;\n    }\n    std::getline(file, line);\n    return line;\n}\n\nstd::string get_basename(const std::string&& path)\n{\n    auto npos = path.find_last_of(\"/\\\\\");\n    if (npos == std::string::npos)\n        return path;\n\n    if (npos < path.size() - 1)\n        return path.substr(npos + 1);\n    return path;\n}\n\n#ifdef __linux__\nstd::vector<std::string> ls(const char* root, const char* prefix, LS_FLAGS flags)\n{\n    std::vector<std::string> list;\n    struct dirent* dp;\n\n    DIR* dirp = opendir(root);\n    if (!dirp) {\n        SPDLOG_ERROR(\"Error opening directory '{}': {}\", root, strerror(errno));\n        return list;\n    }\n\n    while ((dp = readdir(dirp))) {\n        if ((prefix && !starts_with(dp->d_name, prefix))\n            || !strcmp(dp->d_name, \".\")\n            || !strcmp(dp->d_name, \"..\"))\n            continue;\n\n        switch (dp->d_type) {\n        case DT_LNK: {\n            struct stat s;\n            std::string path(root);\n            if (path.back() != '/')\n                path += \"/\";\n            path += dp->d_name;\n\n            if (stat(path.c_str(), &s))\n                continue;\n\n            if (((flags & LS_DIRS) && S_ISDIR(s.st_mode))\n                || ((flags & LS_FILES) && S_ISREG(s.st_mode))) {\n                list.push_back(dp->d_name);\n            }\n            break;\n        }\n        case DT_DIR:\n            if (flags & LS_DIRS)\n                list.push_back(dp->d_name);\n            break;\n        case DT_REG:\n            if (flags & LS_FILES)\n                list.push_back(dp->d_name);\n            break;\n        }\n    }\n\n    closedir(dirp);\n    return list;\n}\n\nbool file_exists(const std::string& path)\n{\n    struct stat s;\n    return !stat(path.c_str(), &s) && !S_ISDIR(s.st_mode);\n}\n\nbool dir_exists(const std::string& path)\n{\n    struct stat s;\n    return !stat(path.c_str(), &s) && S_ISDIR(s.st_mode);\n}\n\nstd::string read_symlink(const char * link)\n{\n    char result[PATH_MAX] {};\n    ssize_t count = readlink(link, result, PATH_MAX);\n    return std::string(result, (count > 0) ? count : 0);\n}\n\nstd::string read_symlink(const std::string&& link)\n{\n    return read_symlink(link.c_str());\n}\n\nstd::string get_exe_path()\n{\n    return read_symlink(PROCDIR \"/self/exe\");\n}\n\nstd::string get_wine_exe_name(bool keep_ext)\n{\n    const std::string exe_path = get_exe_path();\n    if (!ends_with(exe_path, \"wine-preloader\") && !ends_with(exe_path, \"wine64-preloader\")) {\n        return std::string();\n    }\n\n    std::string line = read_line(PROCDIR \"/self/comm\"); // max 16 characters though\n    if (ends_with(line, \".exe\", true))\n    {\n        auto dot = keep_ext ? std::string::npos : line.find_last_of('.');\n        return line.substr(0, dot);\n    }\n\n    std::ifstream cmdline(PROCDIR \"/self/cmdline\");\n    // Iterate over arguments (separated by NUL byte).\n    while (std::getline(cmdline, line, '\\0')) {\n        auto n = std::string::npos;\n        if (!line.empty()\n            && ((n = line.find_last_of(\"/\\\\\")) != std::string::npos)\n            && n < line.size() - 1) // have at least one character\n        {\n            auto dot = keep_ext ? std::string::npos : line.find_last_of('.');\n            if (dot < n)\n                dot = line.size();\n            return line.substr(n + 1, dot - n - 1);\n        }\n        else if (ends_with(line, \".exe\", true))\n        {\n            auto dot = keep_ext ? std::string::npos : line.find_last_of('.');\n            return line.substr(0, dot);\n        }\n    }\n    return std::string();\n}\n\nstd::string get_home_dir()\n{\n    std::string path;\n    const char* p = getenv(\"HOME\");\n\n    if (p)\n        path = p;\n    return path;\n}\n\nstd::string get_data_dir()\n{\n    const char* p = getenv(\"XDG_DATA_HOME\");\n    if (p)\n        return p;\n\n    std::string path = get_home_dir();\n    if (!path.empty())\n        path += \"/.local/share\";\n    return path;\n}\n\nstd::string get_config_dir()\n{\n    const char* p = getenv(\"XDG_CONFIG_HOME\");\n    if (p)\n        return p;\n\n    std::string path = get_home_dir();\n    if (!path.empty())\n        path += \"/.config\";\n    return path;\n}\n\nbool lib_loaded(const std::string& lib, pid_t pid) {\n\n   std::string who = pid != -1 ? std::to_string(pid) : \"self\";\n   auto paths = { fs::path(\"/proc\") / who / \"map_files\",\n            fs::path(\"/proc\") / who / \"fd\" };\n    for (auto& path : paths) {\n        if (dir_exists(path.string())) {\n            for (auto& p : fs::directory_iterator(path)) {\n                auto file = p.path().string();\n                auto sym = read_symlink(file.c_str());\n                if (to_lower(sym).find(lib) != std::string::npos) {\n                    return true;\n                }\n            }\n        } else {\n            SPDLOG_DEBUG(\"tried to access path that doesn't exist {}\", path.string());\n        }\n    }\n    return false;\n}\n\nstd::string remove_parentheses(const std::string& text) {\n    // Remove parentheses and text between them\n    std::regex pattern(\"\\\\([^)]*\\\\)\");\n    return std::regex_replace(text, pattern, \"\");\n}\n\nstd::string to_lower(const std::string& str) {\n    std::string lowered = str;\n    std::transform(lowered.begin(), lowered.end(), lowered.begin(),\n                   [](unsigned char c) { return std::tolower(c); });\n    return lowered;\n}\n\n#endif // __linux__\n"
  },
  {
    "path": "src/file_utils.h",
    "content": "#pragma once\n#ifndef MANGOHUD_FILE_UTILS_H\n#define MANGOHUD_FILE_UTILS_H\n\n#include <string>\n#include <vector>\n#include <regex>\n#include <array>\n#include <filesystem.h>\nnamespace fs = ghc::filesystem;\n\nenum LS_FLAGS\n{\n    LS_DIRS = 0x01,\n    LS_FILES = 0x02,\n};\n\nstd::string read_line(const std::string& filename);\nstd::vector<std::string> ls(const char* root, const char* prefix = nullptr, LS_FLAGS flags = LS_DIRS);\nbool file_exists(const std::string& path);\nbool dir_exists(const std::string& path);\nstd::string read_symlink(const char * link);\nstd::string read_symlink(const std::string&& link);\nstd::string get_basename(const std::string&& path); //prefix so it doesn't conflict libgen\nstd::string get_exe_path();\nstd::string get_wine_exe_name(bool keep_ext = false);\nstd::string get_home_dir();\nstd::string get_data_dir();\nstd::string get_config_dir();\nbool lib_loaded(const std::string& lib, pid_t pid);\nstd::string remove_parentheses(const std::string&);\nstd::string to_lower(const std::string& str);\n\n#endif //MANGOHUD_FILE_UTILS_H\n"
  },
  {
    "path": "src/file_utils_win32.cpp",
    "content": "#include \"file_utils.h\"\n#include \"string_utils.h\"\n#include <fstream>\n#include <string>\n\nstd::vector<std::string> ls(const char* root, const char* prefix, LS_FLAGS flags)\n{\n    std::vector<std::string> list;\n    return list;\n}\n\nbool file_exists(const std::string& path)\n{\n    return false;\n}\n\nbool dir_exists(const std::string& path)\n{\n    return false;\n}\n\nstd::string get_exe_path()\n{\n    return std::string();\n}\n\nstd::string get_wine_exe_name(bool keep_ext)\n{\n    return std::string();\n}\n\nstd::string get_home_dir()\n{\n    std::string path;\n    return path;\n}\n\nstd::string get_data_dir()\n{\n    std::string path;\n    return path;\n}\n\nstd::string get_config_dir()\n{\n    std::string path;\n    return path;\n}\n"
  },
  {
    "path": "src/font.cpp",
    "content": "#include <cstdint>\n#include \"overlay.h\"\n#include \"file_utils.h\"\n#include \"font_default.h\"\n#include \"IconsForkAwesome.h\"\n#include \"forkawesome.h\"\n\nvoid create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font, ImFont*& secondary_font)\n{\n   auto& io = ImGui::GetIO();\n   if (!font_atlas)\n        font_atlas = io.Fonts;\n   font_atlas->Clear();\n\n   ImGui::GetIO().FontGlobalScale = params.font_scale; // set here too so ImGui::CalcTextSize is correct\n   float font_size = params.font_size;\n   if (font_size < FLT_EPSILON)\n      font_size = 24;\n\n   float font_size_text = params.font_size_text;\n   if (font_size_text < FLT_EPSILON)\n      font_size_text = font_size;\n\n   float font_size_secondary = params.font_size_secondary;\n   if (font_size_secondary > font_size || font_size_secondary < FLT_EPSILON)\n      font_size_secondary = font_size;\n\n   static const ImWchar default_range[] =\n   {\n      0x0020, 0x00FF, // Basic Latin + Latin Supplement\n      0x2018, 0x201F, // Bunch of quotation marks\n      //0x0100, 0x017F, // Latin Extended-A\n      //0x2103, 0x2103, // Degree Celsius\n      //0x2109, 0x2109, // Degree Fahrenheit\n      0,\n   };\n   // Load Icon file and merge to exisitng font\n    ImFontConfig config;\n    config.MergeMode = true;\n    // ImGui changed OversampleH default to 2, but it appears to sometimes cause\n    // crashing issues in 32bit applications.\n    config.OversampleH = 1;\n    config.OversampleV = 1;\n    config.PixelSnapH = true;\n    static const ImWchar icon_ranges[] = { ICON_MIN_FK, ICON_MAX_FK, 0 };\n\n   ImVector<ImWchar> glyph_ranges;\n   ImFontGlyphRangesBuilder builder;\n   builder.AddRanges(font_atlas->GetGlyphRangesDefault());\n   if (params.font_glyph_ranges & FG_KOREAN)\n      builder.AddRanges(font_atlas->GetGlyphRangesKorean());\n   if (params.font_glyph_ranges & FG_CHINESE_FULL)\n      builder.AddRanges(font_atlas->GetGlyphRangesChineseFull());\n   if (params.font_glyph_ranges & FG_CHINESE_SIMPLIFIED)\n      builder.AddRanges(font_atlas->GetGlyphRangesChineseSimplifiedCommon());\n   if (params.font_glyph_ranges & FG_JAPANESE)\n      builder.AddRanges(font_atlas->GetGlyphRangesJapanese()); // Not exactly Shift JIS compatible?\n   if (params.font_glyph_ranges & FG_CYRILLIC)\n      builder.AddRanges(font_atlas->GetGlyphRangesCyrillic());\n   if (params.font_glyph_ranges & FG_THAI)\n      builder.AddRanges(font_atlas->GetGlyphRangesThai());\n   if (params.font_glyph_ranges & FG_VIETNAMESE)\n      builder.AddRanges(font_atlas->GetGlyphRangesVietnamese());\n   if (params.font_glyph_ranges & FG_LATIN_EXT_A) {\n      constexpr ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 };\n      builder.AddRanges(latin_ext_a);\n   }\n   if (params.font_glyph_ranges & FG_LATIN_EXT_B) {\n      constexpr ImWchar latin_ext_b[] { 0x0180, 0x024F, 0 };\n      builder.AddRanges(latin_ext_b);\n   }\n   builder.BuildRanges(&glyph_ranges);\n\n   bool same_font = (params.font_file == params.font_file_text || params.font_file_text.empty());\n   bool text_same_size = (font_size == font_size_text);\n   bool secondary_same_size = (font_size == font_size_secondary);\n\n   // ImGui takes ownership of the data, no need to free it\n   if (!params.font_file.empty() && file_exists(params.font_file)) {\n      font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, same_font && text_same_size ? glyph_ranges.Data : default_range);\n      font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);\n      if (params.no_small_font)\n         small_font = font_atlas->Fonts[0];\n      else {\n         small_font = font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, default_range);\n         font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);\n      }\n      if (secondary_same_size) {\n         secondary_font = font_atlas->Fonts[0];\n      } else {\n         secondary_font = font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size_secondary, nullptr, default_range);\n         font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size_secondary, &config, icon_ranges);\n      }\n   } else {\n      const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();\n      font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, default_range);\n      font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges);\n      if (params.no_small_font)\n         small_font = font_atlas->Fonts[0];\n      else {\n         small_font = font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55f, nullptr, default_range);\n         font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges);\n      }\n      if (secondary_same_size) {\n         secondary_font = font_atlas->Fonts[0];\n      } else {\n         secondary_font = font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size_secondary, nullptr, default_range);\n         font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size_secondary, &config, icon_ranges);\n      }\n   }\n\n   auto font_file_text = params.font_file_text;\n   if (font_file_text.empty())\n      font_file_text = params.font_file;\n\n   if ((!same_font || !text_same_size) && file_exists(font_file_text))\n      text_font = font_atlas->AddFontFromFileTTF(font_file_text.c_str(), font_size_text, nullptr, glyph_ranges.Data);\n   else\n      text_font = font_atlas->Fonts[0];\n\n   font_atlas->Build();\n}\n"
  },
  {
    "path": "src/font_default.h",
    "content": "#pragma once\n#ifndef MANGOHUD_FONT_DEFAULT_H\n#define MANGOHUD_FONT_DEFAULT_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nconst char* GetDefaultCompressedFontDataTTFBase85(void);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // MANGOHUD_FONT_DEFAULT_H\n"
  },
  {
    "path": "src/font_unispace.c",
    "content": "#include \"font_default.h\"\n\nstatic const char ttf_compressed_data_base85[178490+1] =\n    \"7])########0tO6'/###W),##1xL$#Q6>##U[n42f)']<P5)=-'5N;6aNV=B9l7_2T->>#tG:;$Z2XGHQ=WO#/HAi^K@tc3DJk7DQO2$2iO]._b(35&*a(*HMY`=-J3S>-x^Nj0#-0%J\"\n    \"f9-eB0[qr$7[.nT7-d<BOZl)2u(@cV%JdD4AJr9.)A,Gi(Xx%Yw>eW.;h^`IIo]7C2N(<-JRUV$g3JuB=]G%`-a8]XL6YY#EK[^I5a<a&%&5YYU2jq/+>00FPj=m.,*m<-dI0h4l%S+H\"\n    \"&Qf$p-gHo[AYqr$EeFVCC&4$.T&BDbLNr'#dHuY#EC(7#.M(Z#u7`'8Qb3G`fNE3k?;%)3W?q?BWOap%0=Im/s[(##sD4;-DcrQM`>B`?847;-*lBvd(+JM'W?]c`7nN&#VHv0,xNa-$\"\n    \"Wo8gL.Ag;-'YP8.B)B>#(ok&#B=vu#+(:B##Su>#aH`t-U^UANSn_aNu'^fLD4pfLHqDw$2+RS%6C35&:[jl&>tJM'B6,/(FNcf(JgCG)N)%)*RA[`*VY<A+pT9e?k8,&#a3=&#e?O&#\"\n    \"iKb&#mWt&#qd0'#upB'##'U'#'3h'#g/r1.]8^kLA*nM37Jr%4;cR]4?%4>5C=ku5GUKV6Kn,87O0do7SHDP8Wa%29[#]i9`;=J:dSt+;hlTc;l.6D<pFm%=t_M]=xw.>>&:fu>*RFV?\"\n    \".k'8@2-_o@6E?PAwKbKc'O%1#.M<1#<4B2#TwP3#d9v3#iQD4#kWM4#spr4#uv%5#%3A5#'9J5#-Kf5#2Qo5#7j=6#<,c6#A2l6#1gY+#L$S-#EE=I#A;L/#0hb.#>L`,#VKFI#cF31#\"\n    \"sq@-#Q<+I#D0f-#,Z.H#6b7H#rvI-#4ABsLs=X4#YsH0#HdkI#aQHC#x[FU%5bt4J/9v1B%;NfLikdV$u$DJ:iu#)<ki',;'x(M^JgX(aQl2;?+CSY>-9p92L7?>#BJqJ#nhlF#O.e0#\"\n    \"-)[0#5SE1#=x&2#=lj1#w3/vLUrZYQWc1MTOw&Sn@4tu5vj^]4A+=>5-Z;;6@l@A4KsBSIKXwv?igWV$TA@D*ZKbHW53F8%db:8.*mCD3uCRm8tT%H#7U5j#`Ano#Frc/$:c$4$P]eh,\"\n    \"lv@=-FZF>-V5:?-#YEA-L.aL-54Lv-#nIt->ZXu-[lHw-fV+'.#Zo4v/]b?/Z9F&#AK(xLt>E?#jjBB#0v)D#2YkR-.n7^.[;eo#`b0W0*U&U-96f=-YDOJMe$c(P:wjBO1,J6M3LV(v\"\n    \"F*Q7vP]q3vKJU3vC213v;pb2v6dO2vt9;0vTfteu(diOu8)eKu+YdnlsZVClLB2ClF*dBl)os@lYLk5lwX;ck6)PekwM]dk^H)ckWjX]k5moE8ml$hcR?%@#q=8a%uvV]+QpNJ:rHSP&\"\n    \".su(3kCkZ2,CS<$$Mwm0Md*P(3IL,3+b<:.IZD.3m]WI)x3vr-=n/K1cs%f3sJ))3x?7f3JOQh,aO5rJRm9DEK'&JCt)/E+_I.[-^deg)MQ[^5NaW&5IW5o/q,8(svA#)$*eJ+uUo7T%\"\n    \"(2.o/bD+H=e:`(,-%9%>1nVJ<X$++5W`=CHD05##P.>>#1u9'#-Mc##b+<'#A@7,=*5G>##kn>#'k&&=4UA2'r,b;$.%[8%947W$br9&$vpFk0jn0N(NkY)4w?t&_YftAu$T5Fug$itL\"\n    \"7S6##2tvC#=M_PM@m<3;NDWC?vfP>#vZs%=2`Cv#3%M$#/s1K*Ia8U)sq[b%BXj%=Ct:B#WOs]7WCpF-d0ju0[aNL#hK)s?$gxo.EwtNFL/5##n5YY#VMwI/tbnZ7PSofL)<#gLY@R>#\"\n    \";);Z#97VZ#9%78%Hl7[##(ZQ8>IET%8ckZg%eT>$D*&&,47?c*$DXI)ws*1#3Qr0(5qZ0)k02N()vsI3N#G:.E7g;.B]fZpue-lL;c1p.Ae]ZKKjp0#%^2*@&2ei0^iVR#BA+*r[eT:g\"\n    \"r;4a=W#YEM9H?##'vgK-=G/e%G-^f1Pps+;nMDq%ABGn&+DY>#98c?#:=[S%;>n8@;1[s$47e8%;/.O4W10*#?XwW$r%&(#hSR12EKRl1Dpl&#4q/Z-;97p/3?k2(Dq1DN80r_,]YVO'\"\n    \".q1DN@p=j1p:gF4$UD.3FH7l1um7W?dl@d)4(XD#XbN)<Q=Jo*0^Dk'`i^CO7McTGHh:j(?w*q4$Hv/(S]b7K8Xdc*(NU(C_uSP-B:=9/Ipp49HRPQ-iN:H<+@^17OK=B,Ah-'5'bn@d\"\n    \"704kkCD$kkf-(,)vAYc2gU*;?RZ7R*T(7W$gf,]3@F[S%AP3T@8c_;$/skZ#2;G>#'et293-K]=+&###R5OK3Zn?g)@JG##r7k.3VjIp0mCE=.Go'J)1DS5'I$XX$85>##VA`0(vuK8.\"\n    \"L,B.*[*'u$BKc8/s<9-mU#+jLYIbn-rUA['YcQiTQ:+;/_*+HpI'ie/KD56Beu`50x,H3'v:#_+ta]W.NR6w/^cH<.s:,_+[vC0($/gbinq2u7HN0f3'-(<-E4H;JIH=>-N?h:HTm[a7\"\n    \"HODsJb..A6PI]],P_i],5dQY5S8q'#](N%$m?O&#piLY7u.dY#h_&*#tUBp7g,&F.]'m+#'.ZQ81S:v#)B=;$'u,m8`ovs.rQDq/?28L(2#]d)aW+T8)CGH38%1N(#w8s7]bj5Aj>%&4\"\n    \"(V'v5_b>g)/vQJ(,2S[():np.)Q93C=*c,.rV2l0cBIg)1D&#mPA)e=oAS[,wDt$6t.9+CmsJ23YDc%,'Asm9(#+PAl#?8.$),##LuvC#KLV,#Il$V8Ob7p&k3qA#EObd8RB0j(X[=_/\"\n    \"oRi*%BXj%=(ok&#aYbv%E-i#$:Xew#;v'W-lsKaP'mN71h)i?#gG(7#M?8W7ejXZ-;tlanOC0*#%w]]=8$YJ(VjUq)-a<A+>>.Z$wiic)pK/N(Yt-thWdEj1Cm;hLnjuH3)CJV(t,?n&\"\n    \"2Ne-3L]=Z8[+U&?x#uBCA*I0)hc6m0sDV-,+C,%$:E9(6qBZFI*b>Z.)>>##@`f&#P0WmLa'U]=JB,<-%uSE#e4Al'F.)$#`KKY$M1x*3jA[L(s3si0jfE.3(P(H-=:fT%mtu$?G)?T8\"\n    \"<(jL3bXBp&$lbM(w-6L.,Y*'utQVh3s#EB+wnrV$A-R,*W^(&MN.XG#Q2.w#]4i$#=0J?##SrB#P+5gLi]_:%Zk_a4,g;Q/F]+&+Q'vTJp_UN<(u`=0B(v#BIMP%LQcvdECrD:Be*>Z0\"\n    \"O;Li<*WTG=cIE/(g*SP&lZ0[[=lj]7Ff1Z#+GcY#-WUV?EL?)=SaFn'q+>V7?,>>#T2QeOmO$##%3xu#pFc^?o^xB/]RNP&0A58.'eZ0)r&;d2)wZ)47'8MZ#+-Po$AH'[.%U-HjATf:\"\n    \"*a>SIuW5^,Zp0pplt)3&E7M8.D])>1MDhLgA3q6*?bs&5?#YM0V[(16/%eX-.wK^uCn[xC@`x&#]#'2#0-ex-(d=78Tbb&#TH9HO6D6a$.H*7N[Ulp/bM@;6]*X:2ltVmL2cJR0QW'B#\"\n    \"a+7Y>'8Wc8XJF&#r5N506:WA5&t^I*j6IP/h`Rp0h=2v#i_&*#6@o#.+]hE5(wS]=2L82'jK.##D_m(+Qg?D*Na>j'_=o#.[P^88C@-$$4.,Q':**785W?C#FS180^aRB5(;#B5Q6rhL\"\n    \"xa)l($x/C+L&@hEnMQR&W2f>64$BrQT^:#.TRqR1jko*=qPH.UZqZX-*K*A+Fd8e*`K&kkJ]/kX]0+m/R@-5/4Svu#+E7`$8_8m&;[(]$e5K<qX:no%Hv2;6iiqB#HgfX-kax9.5Ta-Z\"\n    \"Uh^KI2Sj:6JX65AUqtv-(p/kLMoHlL$EH&#r[/(#*;cY#.K`,#+wJ]=*&###uT[Y#QW+oL#(Bw#2?ou,+8fL(]g>n&MBbA#u$Dnspq.[#9OnA,/;b9D1I@x6>J))3>U^:/0pvC#CV180\"\n    \"[ZIB5uqxD#IAOb)=N$TS_Y_Z-T]G<.h5&12H0iVI:_uE2miZ597N_QCX5OJ-@2`]0oiLY7eY(v#BLMmL6^vY#Nt[(S%=BK1Vax],.J=.)m_HP/jg&(So^0#$#5ZH.iF3]-ndAW-UK5[T\"\n    \"5W(<-eW;^5cD^Q(%)XE*QDZ]uY_,@-,J>C+p;4+.9ZY]u/'xf$ex4V&.u.),[s_>.&Ysc+DBALCp90v7a4n0#uF)20`;`Y50,c9&_?]f1OE:q%VYA*[X8,##*>cY#/&O&%8_8m&uVmX$\"\n    \"W:jl&8`($#lgn0#wYIvRvDg;.]L3]-:[TD3q1-v=,4iLgwV_oamaG7eku;5FngG7eWYJtCu(4GMguQlLIt[.M>M.U./VC;$@CXr.+Ex>#gZh?BNPuY#>xr62YiW]+_MhZ-%6lk0p<6g)\"\n    \"d1)W-U.^TraTL,3x?7f3ICuM(8J)]b5BGV/a)=$6*6^M#>Y'/)pJY]u&]KNCXqtD>0U;6;VQ-/2Z*Cp9&v:*nfww5/jvK'#C7;kL+)j;$]D1pL$@h]=0S:v#PLl>$biuw0fJCZ-ZlW]+\"\n    \"P>e;%R3'Q/%NCD34tFA#0(rP8Oq*H;=J&v5u'7]6/xrB#OY*4.^7Ws8vcEm1x42W/X)9<7rB,N'&)Se,vf%4$uKj<7`rNhN>po0)>$=F5HW(2;_:9xX:8e7&N.)&9[P0K-Nv%v2<t9'#\"\n    \"1qVV7@2G>#%3]>#p<PB$pNR##N6+=$j9<?#HxF)4#1eF`6Vt]u6]X&u'V$`CB^V&#1cEB-Q7w2M,'#)#U=<K*2chV$lmWV$0M1v#8A9^%-Pc>#.wGpLL`;v#H_+T%E]^l8aaJA,2_cL2\"\n    \"?s8b4]`MP02vm3'[ra]+DwlH3*W8f3mOo$$sa*wp7DXI)Xc=Z,qm<:.%Hk58]Q3A'm;a;=%GGQ'Ngg&=vO?M<_GD4'OJ2.R_YL?-HGJ60<RS8/2+ST%mPUZ-h]`@@5K,8/MqH0FMgJd3\"\n    \"5J'b*i]PW#UE.6:;^)X8Hh9A7j$F#7,Oc)#(j&kLr,u%$m-4&#scCY7^AP##0cLv#3&hWhAG9HMI#b?#RHYA#;Du#-[NW-*`a5n&L6OA#+mc2r#4?&%Zt;8.TekD#vcMD3rQFg$_vYD#\"\n    \"+87<.#/CX7B0^n/[$Q7ePf/F*hp6N82'9<7WU_b*XGE**o_U#$1u&L;F_=H5iKWkB8/U?-j2;nL=#5L)RR*?6.]N;]hCKfLQ62e$>CZ;#-Mc##bCA?$%&###+KCV?-1+v-2'qL;$%:B#\"\n    \"m2Ahu;')*%hATf:2lQR<6mn51#NE^#Rm9LNKYvY#,dQq('29$$;X)>PJA+bOZ_^YQeV2T%$wp4Jr:Ionou^V$6<CN$xFwm0W]*E*$iEonf$HrQZ6b3bUI8874]o.C9i5##i^-_fWqH]-\"\n    \">1eX-Y##Yu$$Zju4`fmCw*)UC[tu=PuYm>#b)Bu%cp>V/BImruh'JU#a[g[MYwWtL]Mo(#TMZ$$k3=&#tIIZ7^n>B#2i-s$nZ,)/*DY>#L2#qrUQ+?#stYQ88+Rs$/CXkDISY>-hvS;.\"\n    \"T/1Z-5r9f)S90q%cI#v,5V.n&r(@j:c$**GMGG:.e#>g-Z7(f)7aS#60&Xk'`On@-^4&q/)=mV#D@;n(,HHe<B`_r*+we>66;ug3Qp]3<<lAa#PrVr?7kBJLekLS.>jTv70oC?#6xH8%\"\n    \"5^(v#W:=,MP^Q##6jCv>0WAs%Q<Bp'Sfp],iv8Z-S;hV.(MbI)U<B6&;rLv#^('#,?MF847QBv-t-YD#WOFb3:5Rv$;GEF3Dus9)YqFb3K=?g)Sf%&4^WvduKunUC/aO@tgskA#-&rdG\"\n    \"o'^>-[S#eQ(@Z<WPQGA4p;M^u_]l^I*;Liu'&g0bqx8;-U-5f%5j<87U088%R4LS.3V;;$(MC;$,^XV$&hY+#w$ZQ8)5G>#1Z]Q(+a;Q/$9uk0@Ir8.Jm4:.*bM8.$%`s*22F8YS2rD8\"\n    \"49(2$x=KU#=k=6#9cq;-oUnf4Sww%#oiLY7ho_V$i_&*#.fh;$0W`,#u.Zs-bT`l8_%e<C%2HP/K-&&,'>=.)IOI@#Tk=W%`'([.#]o-)G&9f31EQJ(fj`#5hZvA5QmpV.vo2o&j39>.\"\n    \"+kRNP=YVAP3vxZ$G*L$.@lx(>Rt1e3Q';F=Y_*m/(h,H6Jii$:t%'tq5]&*#t2wiLiDjJ'wBb?nL#>-;f%$[-kmqc)i&l]#>M.Xfp?\\?O(vcMD3CugXul>67&l@=M(6gF+`h/=-*h$kx-\"\n    \"s]1R)23T[uoKHw-M1L#6$lwE5vqJfL@:>G2Ssxc3Q6s5'4qr+;rmb?K;l1/:Z*xa+gj>n&;%`?#O&+g&ECuM(cS<a3^?ti08VC-.[CL+*PAZ]uH8>>(o)tF.E/#[P;;$T.2qKe<FGn:2\"\n    \"=/#u-+[N]FG$rJ)_2MY5o-Q50PtvS&tmX,;:PO&#,OcH&<&4l;(WFkM&2jc)LT/i)816g)++<20j]eBs1]Rf(^V<&u>Qo.CpDwA#5^qE@Rfd'&#Sdl/wl#RE`(aq'+`Wj$[%lgLpj*V0\"\n    \"2Xof1sq1##Dx=wL<Q4%t[]LxLQcEB-_>2U%=aRp0(>YY#-^UV?vBsM-,Ls'%?Cw(<K^Sq)2;TY,:0p30NBWb$H'9Q/>uv9.Vn@X-ad`#55QZIqlGQR&l:x1(M(mc)x>wA5KZ5o/gq-F'\"\n    \"X`x.C[mmJauQwq$ET#[T#G-5/%GrKGW85##5,:W$3Csl&nGcY#R&r]$YweW-@,5L#Q?V-M?AIxi`V]'Ms0jFV[0ibik,42Uh,wA#14k>Rco^W79,ko76:q#$(>cY#a>tZ%$EeA#I*+W-\"\n    \"=$+qi-p9BY2;@wY`[KNC344tB@Qi-#8%mlLAdbjLaLj$#+D#jL0$1&=1>HX$H,,##(1G0.LU`mLd^j$#:#?s.gfqB#rv9H%fu.&4`N<s/j39>.8#;/(j8-7&iftAu;Y^C64P$u-OL+Sn\"\n    \"sM_lLOWOjLh=*mL#u<$#m-:t%,55##g?%##'/,##AJl;$3Csl&hW]m(onkq&T]eh(_&`,)P;*F3*&E,)bE1K(&S>f&usSgp;AGKUp#2oeKRN+V,x`oI.E)uLjFT_-9DJwBN0X'6]8@Y%\"\n    \"9pwO;Z`V'6#YJL(6otM(T+SHuuB&j-2]GF72KwE7KM*RW)U#?.6V(v##x#xL@Q$##xgwY#4L82'd?:'f#vPj(0[ChLU@P]#<jp,.$7gfL-_kxDFaZf><tvrL;Pnj#dGgq##,G>#f=T58\"\n    \"QDGF@u%18.cIG,M-C158Z.x+M4'22NRlv##,d7#/+Q4b+g69e?\\?fH#d#L05l?+d%.S[_pL`0p@uOd#`-EZdX/djJ%#x2O`+dY1$-;)jV,.Z-a<s3s20kmqc)x83^5KW,o/-_mO.]@C+*\"\n    \"Y.]v$l@=M(gGXi(fRY_+d//C++JDnqV'K>.Lhca3;LHw-BV7m0pPi1+BYFI)39T%#X2rt%ma_c)dGr80>IjT.)&###>Ws'%h9_c)d&d3'C%v##F[Et$,SdW-,<*Bm$JrB#ppmA5OG=>.\"\n    \"gY40QFx7/$m3&w@(8]>8mcj5$OQj(RAtif5:mcj#3t9'#rVH(#/DY)')b,E,'8G>#(Yq(<u8$?$m>2V93N7a+wKe--HQ8@S[Vr]7f$x+2N=lM(F<tXASD,P9e(tXA0TX:.?x-*5:7(p7\"\n    \"KhR'5JN#o/ocII2@Om?.WEpH*X(Sv$l@=M(g2SZRI(Yp7Wn5&QRKl]-UGL#6hZ0>GWa:#.jCrO08X[X-,n/>GIfm'&>-f;-<wmT-H,h)2T'+&#&I:x$+Jc>#A)ofLo^)Z#';u)N9X-##\"\n    \"2i0f)iGVk'*&F-=.C(f)co=Z,hh:8.dxrB#'YeD<lsKd2T3j)?ur-S/+c)Z:uOojPac$w-F*dgDL3;N*E_g,3N3.cTE6/m/<Ora5PL%##V#9pppKBh;L2_dOx2g0'M9'/10bME4w@;9.\"\n    \"4(XD#du;d;.#;Z>*6qB#UD.&4vcMD3-pN@tj/hq%p%M@0cFUF*TJd]uKo-h(iTTQ&93D#?#ZX-*i09>.qJPq(cU'c3k8oc=)PFv8<idU.k44j1Q$@#6-38C>`+KfLVk-##_5YY##t9'#\"\n    \"5'jV7C/,##wfY5&2#Hp.B<1K(exU@e0Bx9.94=`#@HOd[+&xAu6T$`C$),##.>Hs-?hZ.M>uDv#3Csl&gWDa-TZqvRl5p%#iw0(4sbV/)G@xr%Jk3B6[Qr*1fCog(`C;8(E8q5Srw:Z.\"\n    \",Tlr/bdtAu;F-[-BV7m03@pEu;SB(6Hmif<Dg*1<C+Iw^qxCw%FcS?20[M1)*q^#$/=W3K,2o3ZFTf8J,KjbinLKB#+;###bBf'&C^c>[g?R##5>'^%2V:v#vWR>#$wSA=2c_;$Pb`mL\"\n    \"&?W$#t#41#:H(l00=N/)E/W;.uY4USC&l:At_W$QPr+]$#E:oL8n4L##&Mc#%?KU#iw4E9&J@&,*4Fm/OJuX7hx1Z#+)6X$R2,##<##v#+JuY#`-N3(gk/2'i]@L(*eQeM%FD,)ET$6/\"\n    \"%+,;dP3TDRV$EOGW.F3c]o9^u$9F]uQweH#$paT#Moj1#iEqhL-C^nLxuv##b[FW%/d=p7;)Ns%gp-[B7[Z*N:Ix9.jbt3Hhp<Cge_$I?M8<JLO>^@k'1$b[R//'HWbQLMkV?X7R>cY#\"\n    \".DG>#Y9^p9rWxB/^VumL[:_l%nlic)&0fX-ZxF)4blO1^mE`Xu$Q-`WJ,RFuX?Wa#b_A>#iEFM'faAG`+BGY>S)8)=[Q4<-YUjd>fm3WSSS0i)-BAfhx^Q._0#eetrb98[oq'60[W'B#\"\n    \"#cprEwf/J=[T.e-'aom(IQ<R8>TV&#m,p7.PU`mLQ6iH-5De.%1uQ._)HAG`q'uC$3F8(3Br;]bYf,m/?Q$)*(5v>#B,rE@dNr(E&&###bNr0(efqB#BVw;%R/35A$j=tdU3qB#o;`W#\"\n    \"Ho<g4#&P:vWD=*vv6>##om+T+nr^s&(5G>#f]2a+<>I3-31eX-k2]HuvV5UMsS3'#.U#N#^JhhL`5cP]P@ml/4I&r.L/mju.J=]<K:d*._/5##K5YY#94e0#^EX&#&%^(#1cC;$%F[G;\"\n    \"QKXm'qo-W$)I(E3Wu,##IKOu-6(1f)Sees$TJe`*P?+<->GW/%kf%&4TMrB#FS+Q'g)ug$%B_v1FXsZup%,V/T-)*4lbMY-^U.p/(*6K`;W>L1D@.M9@VOq0Chf%-jolMCG@KE*F9__e\"\n    \"k<?^#sYU9V4<pc;G&w%+dGr80-DlY##h<;$RZ=oL-;dH.)*px=U2u8.n)?n&UA^T&+E)K(tlDC=g+?v$E@=T%oc``3*6qB#[P.m;ge4fUu7gS/U3,N':Jm/$t7%(It$>+$51Bu$kcZ)k\"\n    \";5Rr%M?o;-mBml$)^2Msqvwo;*'+B,dZU>?CNk;-<PH*2moJF**)TF4@%eX-MR^fLjWGx63jpf1.j[b*h7X2(<>oU/eqUA1[f+.)dRA_#,lda*OfG&<Jl]iBKZB(6is2l2;/5##CKWU-\"\n    \"I^87.1pb%P;)U]=fstQs8gRo:pc7*+e3/%#kE]30l4tA#UeL).1><o9H?tM(02dd.n]Q_ux(=a%=dSK&@/9pACq@l'x9T*u&cnC>^+UD>=/JSuB4a</G)W-&`VxiL$'1kLaPX`#krn%#\"\n    \"0IpS)UUG^#s%+P;pR6C#;>Y^,n/)O';VP##d>=k2'7(f)jAqB#m&l]#O+.t-?=?:At+7m0LO8e%B+eJ74dt>ns9ZG*`E?E1Zf+.)j9Ut%V_rO'RPaE*vVWb*ex@JLFY%e>oj&I*KBUt%\"\n    \"=kI5%D^o],h'b5&.Z>&#:,Kc$r&pc;^9LdkOF-##w####9NF7%Vo:Z#`IU?^)>Ng1_;[L(%O[X-:?uk0Xe?#@eBOQ'-T/i)0q3L#Tmx%)e@p,2Jnk'+SxT1P*'FJLEg8O(%15o/6ZcUm\"\n    \"Q.g-#R5-$vj%<`#krn%#h>cX7]o-W$j#]GMJkWb$4L@>#iDcN(hE%##PWx],gq/E+@P3<%3LCs?9,*Z6iFYg3gV`G)b'mo79->)4m?*?5Ra0`/AePvcv#&k(vPe51ZEg8SDOsd*X$IKu\"\n    \"?x2l2c3Cd)XTW-*iHh+kKSuh)&A851O:Od)`]D?[S/7+#GKJW7P]C;$#70*#k1BP8;eB#$0&wJ16$(,)mgWq.sV`,)E`/GP-9x9.C=S_#a#$c%<+[1evv%k(?[jE*oh[0$)Jfh1B=.M9\"\n    \"utnP0(G`Um4M]*7*N9XoIm6+#3rC$#[*SlLUmt%=8&QpLrF/W$.Q4?#,CvQ8*2;GYa9a;$4[S2'KKgQ&I(KmA8w%t%uiic)AtlX?[W^`P28Ylu:,r2$6h?aevP6tBC_l-#C9]uG3cP>#\"\n    \"]/uN(pSQ]4F:<;$t.:kF(PXGM'21&=0S:v#P7e^&rqr$#]%xh(`'&%#%kj;-Obj?'[gx9.%IgBJ?aZ.quY*Q1n(?p/v6?V#B>GJLLr7M;)r2[&:;D^#^0A,KvYtn-J>wTM4)EwK0O=G2\"\n    \"A(n>#kKj;-u2Xr$OTi6Nw4OcMjGbV$^_jl&QvCT%I;*F3<.[>#(D0N(u%BI&2_:Y#kT;j%fM5bu2u`Cj+?>2'HC]*@dH&d3]qH/2WdO5;d[4t?>gf6K3j-sZvDpEuWa7e#7=>R<;r)R<\"\n    \"_$CJL+E/SUMOmY#F$Bp.('Ov#c3sJ4'%5.)f>Mk'JR[s$N&ic)bP#68xw?w^oLJZ1%$xENaunL(#U9*PSJgj)r@0#,C$2XC1c,gLbKj$#W2J;@X04m'N3=W-jVfqDiKPJ(5gX&OEhAVQ\"\n    \"tprj(rB]'.Zkr^9ocXvI$6v%.s&niL.^WmLfjJ%#sNUp&J7.<A7JF6'jK.##L$ED+NGA<?U/9EYbP`G)&i15%PMrB#bhR@#S:`80^8K<7<I'bn,9^W7Bnau->l)D+G1;a+C>%f2s$P76\"\n    \"UWB49oe?_usMT+4S=HJ3<7[Y#VdBM''B'_S4W8>,h`Rp0+GG##'9,##v90*#(wS]=2L82'%m#N(p3F$1(s%1(TBK6&B3pi'a+C)NwUF:.WTD.34RlQWP?ti0;.W#1Rm<vLR5mdT6TPb*\"\n    \"[]AB+8+2f#<i(+=M'&LPg-F;H$-DE*,&#7.7`ofL(?UkL.jZLMC@p%#d1E'#Z(]fL%QmY#o^r(##i^l8Ol/f)X6gi'dXtM(gcqB#&4Ar887Sf3Djv<7C6gn/b@$_+i70/,iXVZ#xVP:r\"\n    \"$@pK1/WX^,$,>>#d9%##N>[9Mm#[`*bc<X(Etl+#SXlB#wbgl8)?C#$;4l^.E,#:.')'J3TAA8o,QL:%DXoI#Rg5;%<G;^uOE-@Do@9C-4=9C-R=9C-pw]S)efHGlvwlr-D@*]-=Iq'H\"\n    \"io@d)1O:FGs<i8.nmo;-a/^(%u+'J3[EL4ff;1og[Er/)@3/]OPvib*O$mk.0T1I;[qvWC.tBF,vF-6BDh_Q0pq^c3O2wrB0iM?Iv%;'#&VI#17+Rs$xde>#wWj%=)Zp8.)3,#>IFPa3\"\n    \"aAeL(*J]L('?uk0,T/i)44`[,an7T%K]R_#m_Y)4HeZfC(ttD*j,(43.5.qR6[OaXL&%i-mF#jB#G>K3No)hXAw)#0P5YY#44e0#g-xb%7-&:)&Aip.g_?X-.);LN>l*F3>,x<C:gm2'\"\n    \"/&w#U&2Yw66JAJLi^'Q0eYfY,6ZGL1g%*G`]w3g)jk%qrq_%T.-AP>#VUcm;6]8T]lis8V7$M$M`6,A#`d,tL=H-##/5YY#UFSd;,K4m'@Gpd3BIr8.<8vY$aP]#%#WleX,)(bX056X0\"\n    \"-nB^up%%Su_LhaMGLihL*IgnLc<3$#`bk8&3YC;$MKoRL9]fF-S[`*%eE3$#ei[h(#_Z0)RnF%$2cE<%ed*5]<;)&g7H+BJZcCp#[3Jqu,NGTkI'^E#`p5X$ewAM'YorE@%Y)20<u)?#\"\n    \"HExp7ft[9(Tem##o.o^$BHCD3B[TfLMP[TO73/hue?Q*mZVIlAOBV=PE0sxF?*0YSFVOjLOiv##W5hX-u[-C/hX450%VgU#_[e@#?r;t_8,*D3Oo7]k4*,##D)i?#3H(7#hv4X7*C&[#\"\n    \"h(058=MxL1A$O',9$xX-e`qB#wO7tf_Q/[#i@T>,eL(-'VntD#Qt+T%;2)i0@bL/)<6<-*<Iui(S'Y70ICirA3mvL4tF-B?WWc*9YGpe*)%&U/+l_<--_a$uUOgP'R.=4:`;E5ACJPk2\"\n    \"ppw*5%T^G.vY&]t.9?/DvaQ#$$l+$%'4)nsOYjZ8nJQJ(kUu+DK%,qt(P]5#6:mQ0h`Rp0M]lY#BwbFClO470/#fh(_)hB#7h=k03,m]#`?b,*.h8k3UI'O.mOo$$7)7T%hv)t2svaa4\"\n    \"3t469IbeG*T.bS&&K6o/0@7=-;&@$$/26M;girk:%A'dut'Z03Z^Ew,QksI1bR7t-)`>LqY>TE+@xxe%U;_c;uNBlos2>G2CC/s$)G:;$.sH8@*S:v#up@>#*NI`$+M(v#0h;A+uf.1(\"\n    \"GOes$G<XA#t/i3X8)TF4$UHdPG$c?.kmqc)fH:a#8:Wu-976(+d^7_+a(*A-Cqi`+Z<=t$`OwX-CUgv+bLSU/m.d',@=ui(<_`w,NEg%#Qd7fhjN)>Pcb]o@;SO&#P,cs1,a_V?$,>>#\"\n    \"%?G>#Kqq(EBW]I*&?gw#xwMhh>5+?r$D0o[lcFsTFQLsL)dk8$aL7%#ju_Y7c;,##9PP>#,a-8@btxE@fV1v#;2@8%$10*#<L[<$?CA%#wQ6,*RmniL^Z'r..nw0#V<A49Im[J3>HF:.\"\n    \"o]d8/)$fF4FPo=%rM[L(oYRD*uc>`I0A4K1qF%E54N&S'Y$tP&u'*m/-k'G;*b;w8J`9^>[@A7,79Y?*Nlc>#/F)##N).*-m5^%#v6uw$+Ml>##QYs-aV<dM3a;v#-$#t--U?.MO^Oe)\"\n    \"blpHQpgqV?ODg;.ptgCQX5q#$6Ik.)`9`W#c0(P0qaRB5*HkmBEZsH*-tL7nqhmWCEOB(6)AjN4@5YY#At9'#b+rY7a5G>#pZqv%]UtGM;mlA%.Yu>#3iU;$>>`Z#stYQ8cq&Q/9?$)*\"\n    \"cCXI)bI4I$+&ta*INLD3D>07EK5h'[j-4Abx=iee7-TV-Qdq0#AH0m/$b;DEO*pp9:V@oLR0fS%x7g_#DLw+2U/>G`-l68%[mYv.#90W-n(Ok+$<0W-fjjSpl/QJ(BbLhLtc0>GOiR-$\"\n    \"5/MG#6E@[uRAlwL-VZY#K`KrQK0I9i,r[(#Eu3[7IFA8%<1D;$nb&*#5.@8%72e8@-Y:;$6/I8@AoF^#W#coL5BHZ$/p_V$#Y^l8:r$##k3k:8(dr%4K77<.@e;D+>^MK(0%eX-goj>>\"\n    \"cGv;%g-.1C2n3-Xd2Rl1q:gF4OIugL;4_F*ttBk$Sf8crJo+C+q-8m,731:%(bw9.KuN/2MwkQ#++Z(+-O(d3H^pr.fdt9%4PFO'8OYKLO50&$Q<Pp/u^M&5*WD11/v*E*ZV)q8Q.$[/\"\n    \"dh9U)hDr</`1]7&SKnK)[H7cM=ims.RA[Q0s=$##9MXe#*4l:$mBd1/fj:3;m=Gu'bY]>FB3r/)]L3]-j,(QptptSN%f@qL4CVm20bVs#QSa)#^d0'#3ODC;*+BqD.VM'#+]hV$5JT#&\"\n    \"2(@s$2)%s$%70*#$$g]=2S:v#%qWV$--m+#EqW9%)s.[[pJL@-);E://r68%r3hxRT%g+Mw+:kLoPFjL=bk;.6/I8@.ElXC3_tV7,E]jLl;$##]b#AO/Lx8%3q?OOZ4Dj9p7t]7ONwg)\"\n    \"kE9D38*V80[:LJ)_;XjL[>JX-1mrg(27E:.];/Lt6$BK1gc``3;=bx-]]WI)oikO2_o598O7]>.WP@&4CIR>#Pgvu-AJ.2N;<;S0bNs13(3.(>Iu@T%,K*+30Rr/FV5aB43:/^?F0YX$\"\n    \"-n;f#iJ3x-wZ8:/Vu2=4^5.G<,S.,QI&[+<,P%,QF:Gv.,_vWL^R[m'kej5MVD(cAJ5YY#`nq%F<oL20]@PV-h<1K<nM5&#.V_V$MpX)dd6*?#+*^]=6hxi'r+>V7>@-x%c&o$$m$o/*\"\n    \"Wu,##F?4Y-T4Gl;kmjR8)Ed&4Fi^,-we;Zum;Sa+,B^r.O.Yb*5loB,W:1+$X7#d3/t=Z*f)KA,OGW4'FGC=oPg]a+(5n0#_W_r?(q/p%bQsr$8=RS%D?%<$x?]spkG**4(^*E*A@=`#\"\n    \"jC+Jd*MFfd%nu2E,wXM60t/gL6M-##Vr>r#MHP)M_7:W7E,>>#=,^>#)>cY#wDcY#xdY+#m$G59H6%Z$$KW&48_Y)46a?/(0s7P#Tr;wX4*P:vw-AC@pf(B#@/D9.;hfi';S=OWes0B#\"\n    \"*Gc>#W`s]+R;G##khw[#ESa)#JXI%#8Ja)##pr>#m4058&RP)3V;G>#/MP>#HMG?#,fh;$[D1pL?@R>#/N`,#:C39%:vO?#5T>^=@IET%Aomd+PRkU2U`Lk+T4es$tO#s/63tD<:_Wp%\"\n    \"E7dZ%1Vs]7cA^*+tmP]4Fg*Q1j-3d*TBsH*lJVk'R3'q%<7%@#%*>k0,R(f)Y@'u?l@)h)LYaF3?-;o0G+IV+n00&4CIR>#SMfQ0]sZ*=vnHo1du]51C&Mv-VEHn0F,Mv-dPkE4qeK60\"\n    \"4i_+4rkgQ0:9dxbmG,f*Yr7q9/q_]4<412Dc*[o1d`EW/dBEP2cJ[v.-Q6RCG'Eq:GZ^3MxFbq0$),##/%lm#Mfe[>xen&,nr^s&8<kR/#9G>#uX^l8<G?v6:_G)4xXKl8V+aWB%/5##\"\n    \"+FgM#eT5+#Q3=&#+D#jLXIdY#_^Q&4(&###$%TE#p*Lf)DcY##FR*X$CpUCeOaOD<O*]qJb=@]6bTT+4<#BF*W#]h(:#?0)YbBg<=O-<8kwxW7JTBt.2Ioa/ifXjLW?Q:v+O:nNBIQ]O\"\n    \"]W7DEH2?5//iO?gaDEPAH#?lJ-K1[[4F?5.j3<&FjduT8;:w8%+Ntr$j[+gL>+Z`Om@$##0Suu#ZJ4g24/F4'?L82'`2Mk'?xU?#ngn0#,Yuv,sg'P3%I4GVUjfM0$#nx4I@n>#n4058\"\n    \")dEp@?g/&$($m+#=ORw#0-8>,)GXI)ZNgQ&K6OA#nlp)5$rXI)55%&4xPt]Oj6_iBnhoQ0VSmlPfM@h(68Ve$j_eM0A10Y.;S:@6VwDD+`&K&,n[61M^OJ#M;@v2$fke%#GCMkL*^vY#\"\n    \"oDT>o`60v$,DSfL^c$G*`d5n&EIIW$G$Lu]ApoA,8gfX-/-6fE)P_s-O/aT/g)1P^mG5<.Ms*.)w=-m/P)G_5LP+=Is&Fd*jU$1M@ZSo#T4A9$<5>##FE.,DZd2[$GhDsuv)VOBlTLfL\"\n    \"JF-##Z1.[#_qg[1I^fW7M>Y>#'8>##SMe?Tbwo,;a6Hk(gbtM(_&`,).uv9.oajiE=t1I3J=UmEkh;a4IQ,o/R[*m/G'WSRpaKA4hjSM3qu<</Od@fh[u+>PwD88.t5P_&UVc##4,>>#\"\n    \"06S^Hf;?T/mRIM'*pb@kZ5,ugl)-&''Dq8.XQB<1S$Q,g_Lu(#HV3T#[_P/$VYu##Sc)^#%,>>#<Vj.FP#L#$nH0K'MH/i)k;oO(pso?\\?JhWa5K'(]XV*420(p%31E=_J#/@S9$`@%%#\"\n    \"P,66)Ol#m8b?[A,fEbT%IZlf(C?+<-(88^$kc``3_:GI)RJ))3)?E:g5vnqJmtZ?,xog/-WP<'4<#BF*V.(+*1Lxw#x2A:Tb$Hm'bT180M@m`uPBXg;kd?W.w4;'6l,:q%W:;'6fr4c4\"\n    \"DJ8d)04.Q/KW(5Q,YIMd[Q1EO(o^mDvYhuMx6K*#>T?D*tE*)<Shvu#H#[`*Grw4AFT8G*8.M?#mGcY#3+iZ#7,Y?#=:[S%7ARs?.Yl>#@=g2'4Csl&,fWP&3^Nx%57'L5]owN'+/###\"\n    \"'G0b*uX'f)u2%Z>R%:3(i9<?#XQ]s7gQl'&3NF:.o#b1);e=`#52&L;L2.]XHX3E5(JI60kQ&w9Y[X&u)2q^#iR&K1m@E1ph$<-4tKB1p'FU?^E3gQa.P7Rax:]o@Nj0[^.cqZ^k@@8%\"\n    \"AtE9%@DQP&?*KQ&'48r`ZUjp%Y]NdM>5`HMY<ws.Bb2D+(GF.);aBn/*8H,3;Ca8.ANCD39Nn)P^Qrl8Dv?F#0%Y16gMGD#&@/q/esk4^_R%N:li71(mctj.Q5c$6MmvI%Ic@(#';G##\"\n    \"g44R-XAIn6B4i$#VM&`7[(XP&Ob%[#p@9586=no%BYw8@G9L@.mRX,#<?T]=LUIw#uwYQ8EH#n&9.,n&0Qt?#+hj%=iDfJ0P@`;$*+BO1'KdXp>i7I20GNk'G9pM'6?T<-wS?i$4i^5U\"\n    \"eJI#%m@6u69j0J1rU$I0Kfs#RJP_du%LSQ0:#=,W,Ii0(B513MPG<qME@b1BQ']W-&7T</v?[Y#iJ_i'4GIA4fh18.69=^6,Vu>#?1:GD^O=gLaNJs$(*,##.P(v#)KkZgx87gL6Hj$#\"\n    \"@Aei*3>JZR4RXD#`Q_L;;$Xn0bl@d)Lov[-L3rI3sh;.>(Db]+h+h#r[wd42`t<W-@Jqh=I[o(W0hBuu7u@.%+=rr-_?o&#&o'eZ_i?8%f?%##KKfi0U/Nk'Du(Z#Px.R,(Gl;-S-:C-\"\n    \"#tV_-)1%:;Zw[&6B=3T%/g9CS^u$s$6vNx%FdUg(/H)%At]Q3'dVI-)6.JkrxQrs-=oc/ZZ4DMM5=pZ7$fSm&;rUZ#n73jNV):6&];@gLWSU<0EW^v-8lXi(VS':De9lPTj42GDsuDs7\"\n    \"1W*(A-YG<%=+06&r5=sQ(W8L(cf3I)nueh(^2M0(LfGp&K/A'.h+'p7/Nm0)btHP/>jTv7=ohV$PQHh%Rp98%hq2t_tx*GMON-^=F**aEe7`o_#4L+*(ROW8a>),)Nmcj'<<,Q/2;2T/\"\n    \".cg/)tk%T.*bM8.M3or'0(m]/P.k$UOQC1U,UvS/gV46(.&=e)e,D0(i_7w#WGiA5Lk(+r2`lM'c<tx-9h(G#*]2L(76*5(Q[`$#D3=&#n9>'$Z(V$#L6E8;UYWC?7P?>#.c1?#1#US%\"\n    \"37nS%6p=?#&*T&=2Ep8.)w8&=JONs-K@cKVv_;;$lsGQ:3JZZ?w]###jPr0(Gx/wJrI4**27E:.6KbV$s_-lL_54b+6ax9.>?C6Gkh:rdd7oo<NOG%$R$3xt.l,3sIp9^uoMO*vfbA&v\"\n    \"+3wiL2CvA#(S[Y#oWt&#*JY##E$###Qb%lL4f[i$Ng:6/tl_V$UZ+oLSR,=$M3GA#)B]A,,?PA#'IEY->l,?,2)(lLq^Z[$/LPfLX.w1MD^XjLT7OG%I`g/3^pY3'-'uJE$[L::X@H>#\"\n    \"1OEW-=AE0?-qrlfljd.%nWbd8HEj0;1BVC?B1*?#6YP###oDU`@Zu>[L:$##Mkw;Hhu^>$oGLs-0IrKM-Ifs$d3G=2U-4K*?YG>#dVI-),6$:9KR8KUHL%f$qu.Q:.T7KN`#1q%SI%f$\"\n    \"_GF)=$P-h-3,g6E3=%BOI.<w,N)>>#_5YY#cK17#@ZUI5Kd''#^0%J&6mn51Eg0aE]J5j`Zm5x7QaPY<@CRs-*e^v7vnjd=hA$i$9%=gWoM;T&1gvnS7`Jc$e,6W8_]kdM14ab$d,JjD\"\n    \"'.%##4[fi'cc*s6`5HJ(*;3>5I=e>#.JcY#sIpl8Q1]p&s(Rs$QETW-<*7*lv@Nk'TBK6&FKPJ(h]qB#bed4%NCuM(k;oO(L#G:.MjxM&p.%i-^FL+*QGd]uQq.3UcpTIuwWXY1(^)B#\"\n    \"Of4;?)Y4duvX7m0iEk8.PkIJ1NlC)4M7W20#2?5/S_$##2QUKE+0,[7vjUV?ED/]$@4I8%6G*T@7:.<$,aC;$1H@<&aw2w5;SG>#(U%t-@Xm(+w+oh(JU<5&QG@L(5&il0I8T[fa]27#\"\n    \"/l1x/`-*g2f:330Fj3e3i[O@$&Lg;qat96A#%e_#DlU?-ZCM?#Y6'Y$iO$##p+%?I-]R=8>MgvHhAE;$[qas8C?#W./1M9.5S&mAY,l8.($gx=,0oPA5Y7a+3^5C/PMG##'/pj1[15f2\"\n    \"3@bc2NA,G4Gn&+O%7EjTG5q-%ru.Q:f(=<)X]G*Re4m&F?p$<ABX):1+9%U9%74^6]Yp+4o(5c-.hrJWFP)Y$qvp;82c_;$5>?9%9x-W$b=#=C?#0>C2OI1Mv/P(5SV,G4Cjje3Wo#T&\"\n    \"VxF(#>hD]FdZ?crULRP&=&Wd&em;9DL*tM**$4Q/eC4D#?S(XJ1+YaIUb7<:;9*<:3ZCtJ011^Jm####0cCvuCfR)$Dxw%#&K6(#D*QX$,GP##IM.$$O5.1(.]Cv#388d/,')B-+S1v#\"\n    \";3G>#s@O($4`3/%Dipl8[ak;.:=q(Eo9(S2w4.5Jmqf]?w`,##g2P#-bsGn&F)sx+U&Qj'C$]I*UYf)*>[f5/AUr8._1XiKV?d0))>WD#vu.&4uW/7/&B;T%1f>f)i=+</i9TY.U>'r.\"\n    \"Ofgh(j39>.eS.P'hGXi(U<o^)p5A_+lh)m/qsl,69gD>10PFW%Yj:J;*owt$&S4k'Ed8e*P=LX#Xu[X-hl####)>>#P5YY#`.Tk$vbZY#ox6V8&EiT/rj=#-dFd>#4OD](Q5G>#<Yo(4\"\n    \";@h>,sQ#X8&<.(:3^?g1N_=A-/]u>#p]C;$m&$Y8c2Z;%e)Ik0`4H>#N#:;.NQo],$3Ss%E32ao(JHs-uHB;8IUvV%Ms)Z-Fm@#/XG$W.8XlgjLqp(4AeH?,(W#aETQ;h`]W7DEc1?5/\"\n    \"_*%##pI^l8X5At%-55##,`[3'#^*H=T/[+#64%[#X>gl8II9j(m4OFG*[Q4(kp=G2?%<;$*VL;$1dx>#xt>681]b&#N&Y?GmP$(#c==.)D.`$#8sgZ-#M-kC>p5K)`5qB#bM?p.dxrB#\"\n    \"EZko)3jqC0/SL+4rqsAPmaG7e#?Ek=T),##I5YY#`R5+#(&iY71LGQWan)?#w<M39[6Qv$-EdjsU<l31b>:Z-6cbI)0g0H3nrZj'xgFp.Xc=Z,IVf3OkNXLDvR(C&T/E+=;En8@GuEb3\"\n    \"BgdC#Yv9%%q%81(*;kE*X.YgV)vpf)gI>C+P'rn12,jH,njx6/2toc;F'J`49'up%>DXQ1uLT90dK4C5]OJ:/]:>B8[2dAuTf9P4Xt&%#I+65/?x8^6;0nr-aK+'#9ICP8*`$s$V',+3\"\n    \"4-xA6efHW.kloA?jwK#$bo8N%8>#$5[1Q>#M^t:.::U+*Ww39%X]3&+quU'#<PEE-K(da-;/3_A,+_,=nqSZ$h6NaEjQZTgX0N?#1UM39YWVs%;IH`EQU#W.j49g/kL8Q0k%ns._(?p&\"\n    \"5xCp770lA#$]-&/ufk,#%Gu3FmVXO2RZnQ8GL*p%1-m+#n3_dM_p-6S'SgY.XGKf37hCO1,:]#Qh+@q7r>UJDK8G^>d0]Y#'HoW:h2+6'BCR8%l&eT-Tq1d-@C(Xqs_Aq/q4nW.'FFZQ\"\n    \"dwgB+ktbW%iFOW/M+=>51l.>>nmX?#:LNT%8d`,#2Mc##l+*jNs(YW%[I=-2Lt2D+P4`#7?R5R0'bq,3uqZ5'_lJ#$1sGNj-Mv&#<Ja)#*Za@.*;>>#vR8m&0cC;$I<Su%/.*p%5&G?#\"\n    \"+wJ]=6P5##(-`Z%&]fu%O2DB#xR0/3)fj9/u4R[-@_v(+G@>$%:4VS.Cp5aExLP)4earRDfGE.3e&&J3XE/[#7rs9)Y-VpT5SDx-,kBloS],G4umJ'+T_@`<BLcM()l06*#TxU*Ddu40\"\n    \"n)1j(tJ';K?qGR&Ijqg(#uKJ).8og1@f0R1WVl.3er?T%NvcSFoA(a4bCq(%wtX)##)>>#h1.[#*4e0#<6>14Kd''#j,>>#`P)T)P+NBFlBpqBG/5#-gj/v-Psb>-a4B>,N.sqB'D`'#\"\n    \"K.@V8i.I21fo*m9o:o98:rNY5S^wh21uH##QSB@%cc_&FI3w_#?P($-rAMk'?iu>#da,;%E:_E[O[H>HsQnA#UKMA.1u)13?aX29Kt5al@tHQ835?Z$jv5Y8br+3)aj$125wq*4DvjI3\"\n    \",JS1cES%mSK<SqLFb(]7'di:%/950:ut-<A?rxb-%Yd3F>&'J3GQR12FBu$Q4s^B+@v9kF&l$##$DR&Q,xR(#4txRn%+X/1$TBJ1SmZ3'B+`;$T4.m%1I/W--?b:U2DZX$&W7L(I[=PT\"\n    \"<@JflnP#D#xpG(#H55T'1f(?#ri_V$4sNx%&wD'%Pa3]%eBD>PaX_Q&AWUK(_>Mk'GR<5&_ljHZC&rl0<(^JDm(Jp8.U6gLRKL&=C=%w#+=mQ8%7Ds%?1@m'<S'<0fV@h(^jYN''KR@B\"\n    \"F,rl03Y@W]U27+#[&U'#r[/(#--^]=.DlY#R=lcYnR5o$Z&jD3=`7q/G[Qc*A/?k0=)3K(Z_1+*XpOs-@7qb*O(NQ/UD.&4/rU%6I/3T%q%NS,sp)F*dKbj-->Ms/Y/B<7)f;X76:ov7\"\n    \"=`jE*KpIw2?NuO0+_pt8-*#114#=Y5$%Mga_r1i:3FWH*l/E*[]2p;-BEdE&Jk%##gPru5JWWf:gT#i*ONnQ8@4I8%Zj=oL9f^^FW#UsJeR$)%47][#uZQ0)ji6<.H3/&,%,]L(W<tT%\"\n    \"?OR[#1jLl0QV*?-i7TP8U]3?-Kd''#oKpS%8aRp0#lS60h^XaEC;U^#6#>^,iNuW%F7H>Hl=-A;RS,lLkeSZ7c6D-kQZ/k9G3Z;%gH/W-Pat0NReJ60)rA02,_:O1YFLIZZgb1:M=klt\"\n    \"XxclL7Oc[7*drN*SmSp7'g8UDNuhW7dxYc4DK[L2tn`OF]u->-r@%o;rO&FeQrxFex[U0Mdb-L23q_k1#.G31Vl#T&IU+T%c,i:d<9%8[-l68%o1FS7Se*?#-]hV$45'^%-V:;$1phV?\"\n    \"YIW-?k9]nL^n-##v,>>##mGT%+/###I-BQ&JVD(=kmTc-/jo2)@O9]$:%xC#vp%$U<O1P8X^O&J,s^DI`lr-#&5>##Nwtm#FYK:#^?O&#wC@Z7k`_V$lc1^#=F%@#n@B58Y,e,E(AcY#\"\n    \"p<WE'31Wp.l>,<.saZ*7XEp30#*Yk0@<_=%a3FA#s3si00R:a4m(qb$sk'+*+.,T%C=3:.bhR@#=Bs*6Vvpn/OVLg0P_*)+uPe51rjA^FF/@;Y#=G]#-2Bo)=kP76]AVI;BH&8:s6e'&\"\n    \"4LM8$-K[IqxeYC5#ZQN09OtA#gcZY#80?>8u.MT/^((f)kE<UK@5_0'N5G>#jhHX-%*=UKWpUX%<=d>Hn?o@bmm$&4LBp>6JTF78NVZ;%4hb&FJ;Z0)K-1,)+x>c*?Bn*N>uOd;Ux6La\"\n    \"&xZL-b5>m;3F+Q'V_,/?K?7.M,ldC+07?c*vI'+*6o1T&Cd4-vewAM'XuZW8cWa$#Qx%8@*`$s$3Nhx4t<CX%'2>>#4LgQ&sxNS7&;cY#91CGD80hQ//(wo%O>7L(i</<-I)0o1[R5+#\"\n    \"S3=&#v6uw$rkui9Tw0'#v0vQ8F</#G-)u&#t9LJ)]D_w-g[sg;H:0oiFBG_hV?9C)c2:[eO/EK1&M&D*4m'$-sjhj(JD?mk9xw(3D8Qs8>BCUi/Yqp7XAE`#'upl8S996&DjqK(b>Mk'\"\n    \"QQ53'ctc6s[Zfo8VU>W.ei<877OU8@@Ei`Fgq3aXxk,K3-2%6/2<T&=8)Is?/D]5'Wtf7&i%aG<6:BeX&9F]F`as+;Xe[Y#OwfZ$sCEh>Vk--b]QpZ$u&UH;^O&+,h&%Y%HBrA#xr8c0\"\n    \".=,)#3fLZ#irH2Nw^h>&8lS/d;1vZ,ODa;9#[@9.B:o)<LukA#r;.2.5j?4Mv%g+Mrh<7%0#+-M'-w^*&O&*42?712)HhqB(o^B+er9T4IoKS.xt529j:X]+x`q%4G=w>#>FDmLif?>#\"\n    \"-<M,#/w&&=3L&m&Y`o6*@40*#7Sa/18d]Q(@AvS/^T9U%gMYZeeZrGDMvjj1Bc``3]lf`*.PaK1WjMP0.d$Y75I[=-dw4l9m@Z@-+=L+*k)WB+RKx],ndkA#[%x2H<P1U8(7*/1Oms+;\"\n    \"pAq@#eFVa/4%%s$7,[8@^nP#$R*Xf-oJqoqiLF6'o`_;$+KXV$-16m8*]-##Da&F4wo:Z-05JL(U6'q%'<0/1EwlH36K?q.A,m]#CmPV`QJ(<--p/^&A,wi1)QT$PtUr`JEYw],P?@QJ\"\n    \"&DSriiv-buQI$##f(058FYbV-'ER8@Mhq@.pL$X7SNo],2/bS7&>uu#_B=@n6xJu%Ld-8@=;P(HujT1;fI=@7pHD/#ws/X:Tsb>-=.)XJ$C0X:CLR29Cgt`SUfGlLv%k4#QNQ8&B&Jk;\"\n    \"Yhr*%@MXSq>4dmRl1QD-WB?D-G`e+PkI6>+j4`D4uPiX7mPdA#q40588+Rs$)?o>#iq?[^3Q*H=kM*R'YYV50Ashl0x_%E4-RKfLQVr]PI*,@MJEih.[PHW.A5*f%O.BmJhR;h`]W7DE\"\n    \"&2?5/I@$##]FOcM3dSZ7.EVL.'qJ]=&xRt-_)$#>^8F',k&d3'?7.[#f=?e4l^w##5>F*$(sC$#^3=&#,7#)#+q&&=;%`v#`krW$l0a:K:^b',[vrx+FBo],+GXI)vW-22,]Es%rDQJ(\"\n    \"uAOZ6CH:a#'i'U%r7q8.uv-ou@-26(KIZ&YroJ7/v<tZ'Lxu>#*4g)$4XBZDIHfM(d93'gNY$8@So>w-IlY$#gBVuPbGx(mwkQ>#DF$G*v14.)b,)O'wmJj(XOtWqafW&#O;^;-wWJn.\"\n    \"`Wt&#_n@a$C_=h>Uec^$)>P>#0v:Z#uwYQ8Fn$HD4e+T8R8CsHoO7a+*eRh,J?%?$YAUPMQTxv6$Rt$#,Qo],VXI%#@#qZ-am#7&D5%&4_T/i)J*)pJmL<$6]vZ)4k&l]#iZn/PSgtA#\"\n    \"#olT9GCm<7D9gn/n'Prj?g_11q*TW(T@`v#`6/SB:q@6<97`RBFAYQ<0hRf**@Es-BbsVA-9Hv$+V3j$r0WmL]1C&=uH<+(Mo`=-M#/c*@7x(3B,6W84UrDN8Ag0%h?/<-xOb2%Q4]_#\"\n    \">_B-)?dLl0gW<q92H5[7pGY##>I3T%Kj@Q-n1O$%nB<IMBtA5'2ctI)bk5nAki7p&CeT&=*:#REs&p(<Mq@'?0_-a$8bVqDMlYIM9uj22fuGG4dm)+=0[I@%uaA_)DRDp7ZvKwBTT<[%\"\n    \"M),##m1.[#(t9'#m7.Z7s4@8%hN[Y#,V(Z#+9A>#vaY+#stYQ8u0`J:`^k6'qo-W$-Ttr$/7?m8Ykk#-5SvS/2Slo.K6mH3f%.f;h8G3DCXOD#cF-;s`DDr9XN-$$gpM.CxU=t9TL5b@\"\n    \"tb%/1QXa'5+R&,2Ua@M9nD6A#m'oB0.J1v#1N`,#CgXveWxF]%mXu.:r]ju/K.RW.DRHc*_TT6&-a,,2:YvX$X)pGD=.dg)=J&v5(k%)]Y@EZ'oxBr7@(5Dk]C['&QUgS]52<r7ne5an\"\n    \"f2:dOnd$p-V-Y`-rRba*l+$##188i1Y####U&=[7.M[S%ZhEW82#89&:Les$P2;-cL:$##qVAQ82o/w8<lS`*%eQ(>JbSqDd@d;-`DX[87K$MNZ%](#ErvN:<_:*4Kd''#M,>>#6+tg(\"\n    \"N>YY#-^UV?GM:<-(;Y_$#eibltA^<$UWlA#C4n[--xJq/>p(B#/bjY-;,6w-If?T.`1.[#wW;m$`4-RE%.%RE7dxQE$tSc;_9tr$4.7s$#A8'$'.gfLV`;v#r;R7*ZJ`B#[p:80M^nL2\"\n    \"$J*X.1KYA#+n]r.)(up@KNJ;i4XEs-P4<g*6&q29OQo`=SQxYPa@CZ-k($dNb)em8ldq`fD?W@I8I$29wZToi[-a;$%0]Y#8chg*I^3HMidf60/.NEOF)i)NuiBM''$+m/<5#5V.lqjC\"\n    \"*#[LcfNXrHMWEh>J$m+#Ss+$G)JtM(_Ztg$GH%#vm,CkbPk>_A6N.B4LF_/#TS;4#Edav%1oqr$7,%W?8a82^aHZY#r+TV-$C+kbw>'%#e7.Z7xCrv#9UWT%5%M?#92c?#9u6W$:a.d#\"\n    \"0:jl&tl_V$)%6m8K`###$]KF*bd(,)$3nENok0b*ujrI3RDL8%ocfA4<O9]$e)?40`tUB0`RV'VsA:ti&v`tL^F0HuG(]duf)3TBJw(0#0^.RN'Bpc;K@9MB&&h;-P:2=-L[-&/$bs%=\"\n    \"h14wRcg2m.8q+j',QUS%W3;O+q/_oI+0+Q'ojFG.DCv5(16ha+au7L(VmwiLi?FE*2P;g),3u,Oo)[)4i7:[ji@Ms/:E1N'h-=<UeMo_4^X.f*i+`9.:M&##wCW1:NlH#6CB:QCLQ<R8\"\n    \"Z<]589.3_7X:je()_^7/c-H(#Un7lLKX>o$h@p#$-Wn@%q_n9.;SG>#coU<-SksY$(.on87bxS8KH#XAHQ/0:hxQw^%7k0:?Hd;`%u-ro,D@Z7gAP##:7e8%=/MZ#1E>=-UmSn$TH(',\"\n    \"#%U+*;u_amo:8L()4YgLmg?>#jGCM'$q*m/$m6A4&^j/<Cn$q7&5uu%7u-W$$$tr$.-m+#I3':%h####/esY-;pdi$CQ1l0%<oO([@%gD1KS^dAQX%ZktMWY#mx#[fR5e#LRMHuC2,9)\"\n    \"H/5##MXY54LR5+#dEX&#D*;*#8Ng&=AXjp%sW6$gRhY+#$7vQ8'&###4>?9%v'D/:;W9$-b;ou,R#1Z-$DnA-;(Ei-tr@OXJH/i)R6u_0NkY)4gp:Q#g6V-PK2Lq^Qkt^C=&&2Yi_dtJ\"\n    \"^tO9+@Ac58@'E'#X]Q(#UPQ_#d*^sTTex3'%qHh1i;oO(ROt.L353p[0#6tLR15%Mn@6##CMG13It9'#;L7%#nOs'#(hs%=PKA#G$?6$$&*Mc#1C/2'6BHm/fcWI)[NgQ&[4&70Omu/(\"\n    \"@Uw9.&B/lB:R;=.ZeAk#%bRB5#p-;(%m_sH0J:a*u@sN0T5-$vuk]&$Yx9hL/.^%#'O']7XPlo$#+9Q&>$#N'kAlY#8c;q%6Y:v#(6TS%^MNr&K+h+*^qr$#uaDD+87q+*.+?c*c$tE,\"\n    \"v[0b*m?bU._kY)4=nx/.(IUb*k$=Q/G<Yj^poP%UjA/k(jg?ae$AEJL#)>>#FCsM-8lIf$qRZY#hV-R9)88dsM7.Z72?<a*'oiW-Guw[>v[T:@8_9N(3owN'Pho20?q82'lcRh(B;uLW\"\n    \"A2oiLFO6'$>OtA#<L;_Av4O_A>Z+##BHe#%/)j''VWO1:ZU'9p@G&b-+<IwBJbET.T5YY#<x-q$YGSwBW>JwBwQx:H6P<]XUH^#.l[=gLU6Mg*Gbk30,c$s$M>Rh(vUk-ZASPw9?Vlw9\"\n    \"?*qjCrd%##7B3STi?9C-IbTn$[p(N0->G##-VCv#WsRfLVW6M*GNsjtgwv>@Uk2IN?pZ##E$###s'P[$RNnA%Zkc+#v'dQ82c_;$%3xu#)%$m83GG>#iX4gL#OHL-r_DI.WT^`3D(H/2\"\n    \"*Fe;-W$tnLsa8#%J:)H4Jv`sfcpS3Mw7J(''ml=-CKWU-e;`iNuG5gLXp(+$>AWi-.c8`7E9nQ8K=]$^-G^MY4>#29]%(m94/Ok=90Gk=Rk@a5-WSW%7oU;$rpY@.-'9&=IXe,=Og&ZM\"\n    \"1fAN-7(7m%+Y$##e8vx4.:2i^jln51hA?I%oE'qR+QsM-x63#MjcAouo_:Y7gx$s$.iqr$)SMmCHIhl80IqA#$b=c/>QSW7PSuY#bw>^#4cDdOc&1'#,Yu##VNO=$.]JL(2'2K(6otM(\"\n    \"/&JX#5?:;$wurtEJS>+rxLrd*tI*n/RDlX7%_5n&-Wi]./>Y>#fwnm%uvY=(pEGJ(p%Oe)iiqB#8<v20m_G)4NaZ&4o_Y)4R#^iZ3j-sZ*]U2$Y20[2'A=xbP;8/(>'CC#7m9hGRu`=-\"\n    \"iHWe$00;W//>P>#6Z>W-*EvX?XVBNEo=AL(F3XA@#A`'#/lR)ZxET_-ws/X:?DXI)%sES7'55##&6,###U,'$c,(W-fFAgOn=kA+3i6m%H/T?nrK'1;vFlD4Y[ReQfvv`*%6=NB_iCv[\"\n    \"r4?h-u*Jk=+wBM'O1E*6$G`'#FjO`<qw=bRhUibR6@j/)>^hr?FVnkX#EIkXfc*+<L@NZ6W0k?#`i8eZHF.D?o2O&FfmM<'+I&N-?G$9%EJrn/75v(34-xA6H^=S(G-##>a@Y#@rT7h@\"\n    \"wjSU`Dj9W-kc<L<1c;'#T,GX7#4J[#m40584cL;$$L,'$wYlh'Q####cGnL(;#?s.klqB#K[ms62k^#$Fl*F3)B-&4uY*Q1::@p/S`*(l/'(:$aMpr*tS;K1[$o@u/gtAu&o7-#JdP&Q\"\n    \"tY5&#*;m^,&/,##uwM.;C4>T8.cCv#NtU]$_SqZ-5F#gLue6l1Enhd->o]cPu*hb*F%KK1,TLj'+pm#UKHs<7jDJnN&9EnNO').&*xAh;Q'sbNNiPrd#)>>#@.J=-o39c.EqUY7Ts+@n\"\n    \"q93*%WSUS%AD.'F&k;W%AFg+Mv^A5Bpci`Fki#aND:nQ8^GXk%?t.RAwhx>Igl)?;LFl98Q[<;$-Y:;$?V69%/L?l(3eQh<a2nh2DM::8g*fA6AP:%SI:NjT;./b-FE3ABf3Bu-rvFD<\"\n    \"6xTB%^`Sn$0]#d<0A'gLaFp-#6[tG%=;E)#>ii4#DZEZ%'>uu#/vZS@%$Y<-fUl0&cF[PB%wrc<;N1U.[Q1,3^E9S)iVfgFx=6##IlK`#3t9'#W3=&#(+g(#)J1v#3>B#&gSBXoUe)?#\"\n    \"qh]/1:DUK*W2SY,6FZG*oc6x-A0;hLi4JH)27E:.H:w_Faa?T.SH:a#@mQv$t@0+*sII[#Vi=RDdG]v1YV]h(?WIh2F<4>-kZBS%VCEL1J(0GV<dSk(AP+`uI>8_#26>##.5YY#V4e0#\"\n    \"(dZ(#Gu3[7?(A8%9%)v#jb&*#.;cY#;GT#&2cc##^]OgLDMwQ8.DlY#OsmG2#%TE#4k`)5=eln0Mb?,*#<ms%`FjkWl;ms%]f)T/%UGccC5^I*;E=r7,8dG*x<uT%^<]@6a^=D%&J.XH\"\n    \"4Ms%,`S8H3,xh<-`k)X0+H#*t,1v?,%M42(0NiQ7SweW$S8`k'=TOR2i)U+,lR5jBbgl(-mxi0(KY;6&HBFS(xuDx$x_$##WDq2D(`.(#*mU`3.5+-25'@>%+Jc>#tsb>-1sES77B:=+\"\n    \"t>]Y,,PbI)g82O'Hbn[#0xGo$b,rE@YR)?@bQW2MS9UuAcG0$-M)AL(H%)Z#?XY&#6-,c<E:'Z-Ru'P%--CM'vN^Wo@I3w:/6U2:s)$@TnN@W%HjToIaYBX8:^4#-o_,4%f-u>ecH<mL\"\n    \"j&)Q9TPekXwmt7I+?&##`/;W/cSc<--.#H&&3Dk'i`[h(-aHv$_m.n$#n2:@&<8H<(5wA#o*wW_f'+KN4SK4&EC0*#:$`5J.AEt_Yr_>Pu(]dD-:NpBZZOo2s>cX7k7`V$p?u#%1lLv#\"\n    \"M0`H,4%co7(^bm'fV%l'KsL1.heR3:%R>)4RU/30R,=.3cI=@$CO@(FGJo`=4(Mp&3flRA_EhB#TD6C#'S<p/D/-Q<FD4jL?cx;8&N,<.Kd''##wcT%EY4T/&Ib;Rw6P%7-Z7>/Hu4d3\"\n    \"xtQLM0#Og(_%#'-R$0Z$PJY>#rGal8f-27W[L.t-2;jr?r%7@^E,%m0)/]^.U1.[#nM)Y$N7H;I?A$aAF*=`A:s1B#BlqW$6k=Rah5<Dn($+.AKU?j:4;,%?W_Q-dr-)-M7gFc%aroFG\"\n    \"fcmHdrk)aNFaYgL*uH/80@1B#6Q?(#V.pS/RR%Q'KbZp-i?MqD*cGHMalx6%mlHqDJ)>>#l1.[#F$Fr$.7[Y#u[Al:#PPH3AuQ>#xg/&=A<0<-#rGt&_(;?#B-0q%Q;2'obE:K(PEO,m\"\n    \"(<kr$=%mr-GAB1MZft.Fh]Js7nCYa*:)v=-TC^$.+]gI=LYOf*UZd`*6O2D+Uee@#,UeX-g&HR&nGhx=athP0Nop`NQW[F%X-xA66B2gtUqDv#CILGDbJ'dMU:ho%Bcgl8Er_m'VpY3'\"\n    \"A)Bs%G/d5/Y5YY#^O(.Pgpd##a'[4$>;1_AqK$'#9=*9%X8/m-m?'Tai*iOBT]tm'h`Rp0Lsm`*>#`)<Z8op&qo-W$Y0M4B].q/)'M3]-UOl>5Z_Y)4[o%Jq%pS@T'5fKo?uP)D$<kuG\"\n    \"RMHXJ6@4%$j-4&#;QaV&b4xfLWDAW$/B]Y#rU=_$T*V($5_oi'u7w8%2jTS%oqX,M+L5&#FNOY-0]F_$&#ta*e+GG-?;pn$e.qkLx>OiE?tkD#0pw.S?,Wld(sc@>Xu]WRQlXYCi@eEQ\"\n    \"_B`@>:f(pJ7s#d*XxclLE,k4#d[?ZIxRbA#7^Bb*99.e2`4H>#qE_c33IPn0jrQW.e-s.lFEWN9%5ot'A;8F-fF90%PZe%%Cnm`EegV8&+VRt-b3R`EpBb'I?`8F-aU0_%*u$##w3r+;\"\n    \":#pG3AD1:'MT<R8Mvj6(XZ_>-?;.T.k*LC4F-`W&4wk9.pQ?(#.YqP'u.n6`w)pYDioKdOA,6`)Lg,Q/,7#)#.Pu>#ICXsHY+X-ZnRfi1h]$<.4wUs?J0(KEhh?lL%O&mD@#2_]QHOU.\"\n    \"?Rd(+EF7WA)Z`A.&>uu#kqp,2l2h'#=iwZ7^#;^#m+058v<8K'-[Bx7_a`s%.Y(Z#O)k>5^(-##O^eL2ax@M1@1YI)KR[s$YfEA+@-<r7ut]G3M*I=&DvOZ6m('J3SB:a#EUAj0)eUN(\"\n    \"KtMJ:M[CW-7K'w-<?0o/(CQk.oBdkK3U8EFj8-7&MpNI-iC5C+=kV78%c9j(3+4nM.iSH)Ak8%u*X7m0$So=%bg=v*0hf[#7p-90FhXs%xTit^<M<>5[?LV6W,ZKl^.[s$4^`,#/Jl>#\"\n    \"IlN2EDs2L)i3FG2e#p&,04$K)6+m=&I)>>#P5YY#Bl0gLaFp-#TGJ_'ZEX#7vo8?$(5,##1NS_'&5[#@mMN>,Z0p3VpK&'&MJv`,Pb$+Q@r?>#[sBM'3H+m/12V`3C([>#Z`7M+P]8D$\"\n    \",)###vxdQ/oMPW.Gk2D+5)q8.55SX%AEg8.X$nO([/TV'0c37/oSlr/DMfa*VkC<?P[gv-4=T_#d?]*Hub-*(v4b(NH5:a#uXt&#3^oO(gujo7cS1T.&wfx=D0M](KLd(+h,)O'<]Y##\"\n    \"vD2<%Z6M3b<HZk028Ds/89l2'/&w#U<Y)0),kGD#LXqiW/U]b/+rZS%+g68@9*Bp.S1?5/><<$^9/h,H1H>[72Y[S%HLMmLw,R##6GB#&>q&6&6S<5&8Q[W&[=S+)vq.@#^%oL(#;=.)\"\n    \"G:%@#t7O_$$qNEEak%9&)TUV?\\?ke;-<V]F-5T]F-8]xb-Y%rsD@&^qD^H+W-IR4H,YXaqLh?9V)CiJq8_Ek?#<Lns$);YY#j`9$&)w,:.64%[#Xm_A=4X0j(x9XAFQSjEe`^9Z75vra-\"\n    \"xcN&BYp6HF>cQ_#'upl89PG>#Wv10(>JI+6eD%Y%J?M&#)CwGM2_WiK=:3Ec>`8o:Nr$v9(;AL(N7xe%Q`h<-U+d9'PAcY#/GG>#awi5a71cS7Bd-LWD0[Q8:)Gs'BZ->8L:?uuBdNw9\"\n    \"XZfs7$3*?6Kd''#to,X&0CW:@)TQuSD1,]RQN'2BjxaL>)G5HMBMD2%dwK]@u23gS:I+_.,D@Z7nT(k*jXggU64wR>Zjv/;fZk?#pDWXC=XUZ%t6Y?esn=&;AFYrD8.R<-Vp%3%#4XR/\"\n    \"75v(3FDm89eM*o2@_'?EYBVwCR_l,2SZBM'YDpc;#^U`3@l?>#xml+#u*mQ80S:v#02-9%8hxi'qo-W$)B=;$++-m8dQ-[-%0fX-9O[X-)G#c*4Vk?>+Ng;.Sr1iCd1qN([nH*Xw'RK)\"\n    \";a/iC_xIP^]l?T.l'h-#RJ1MbJVGs31G8MBtqU>#BFrr$q@<3$'8P>#k-Jq$cYG>#wa&&=+DlY#9]md+Wjc'&#$wf;%l9^#i%k0,RI6##bc'<&)Yqr$L;@L(ecqB#6cE<%]HM`N_:c99\"\n    \"@oC)*I(7$IcakxB$MB`N(i#%.`Ix+M-@)&.PmThNlDZY#O<90)w9$`4jkf$NI;8GV384'#&6`c#BmtgLtGj$#t^cO-Y^JZ0)Buu>-AP>#_:SfL<[7.MVO?>#:6YY#MK44Mh;n+#o[li9\"\n    \"JkZgL(k)P(k'Uj(2$Yk0>]WF3I)tI3$3Tv-ePJsn`J)p/v4e^5Yo73:BU&w#Aj0Z-bUsX.IU,H3%V/;/k&&t#cn.m*MG4s/GAHVH*MnhC,7V=/$%Jl#s9b$MP@W$#d'ojM?9$c*lk%t-\"\n    \"Tu[fLer#j'eWtK)(&###+Duu#t%Y7*B1?T'AL)j,k]-f;cqgZHac)T/i6(Z-qws*,4tv_+hABa+hnsx-SF9'vUL?>#q^FM'#k-eZFviu5#BQa<fQx68rED8A0.lA#Pk*J-v.$L-BR`X-\"\n    \"-Pj:)qE=m/mqZX-4qOk0hQmi(WrW`:9qc'$ZdSZ00iOm#G[@%#r3bw71ODh)/x6W$,M(v#.a_;$DX1a3=imd+*)?>#%R<D<&&###.P:;$daTg-)b<@0(Ys]7Q(Wd%I9@D*H3+:.66lk0\"\n    \"))'J3SWLD3I)tI3-<Tv-C0Tv-.#[Y81>at.2.)`+x#wZ.Q4YM(`Z[o[Hghm&spSn/.R#R&H`###WVd_#F1xe*nTV[.0R:a4ElL5/SDIpMTO)uLcc@)*iENfLQ]Oo2E5YY#=t9'#-Mc##\"\n    \"Wcd&#0-u9qRXmY#+qgS@,jt&#547W$*s?W%_kEX$O/O1)ZgKZ-vgJP^U.9]FSZx&&$/gbiaP;4#J(-5/QHT>6Qwi02b;Vs/$4J[#,;G>#54LK%E_c^$loZWB3=CW-Lb1F*06@d)s9Z)4\"\n    \"KJjD#TMrB#jBFA#$Y0f)9,B+4hC]hXlMl]#JA1R'u.NF3oF^M/3R5R0?b%?5?H'-.W1(f)7i+vmf&xg)enax-MH:N9Vt%d4VRsX4+P`pHh79K2?mb+1E)Mv-d[BBl2Ltt.<d&ktA(.@@\"\n    \"0LBJLc?&/1H_&@#i(058TQeLCZjb&>4UA2'-xTk$h[R0)mZeX-sc`,)P5]k;n3-O(W^Tv-6YTN(.:%)(@-Q&>PFQ21KVD/Ua7BfCP#0*+kCN.LOWp6&&OE;HBcSd+^6wlLxI3$#W%j>$\"\n    \"')###+Ex>#vUdYoN7$##x;<+NXltA#6^JeGB4^V6Gwd2O^Z4nE$b#d)6klcE:wK'dH1(58?dlaXv_g/3nc@L(aTc2;)17xGg.lA#,=5H&E57m0TC-X]10QD-8>'5;k`KM>QYK>H;aT>H\"\n    \"loPM-3D//.:?Qw7^S+:&=hap%E[>3'Jm_g(0cje+9Cue)GfG>#(opb*v+4I)bZc_-/n.X-N)>>#Z]L=-e%:IS@7rdMNmZY'M)S&#UY+H*h_Ms-*m9e*n>f9JB-K88b>392?c.i*b_#o^\"\n    \"/S?>#aBmY,gpsc;W?Va'l,e`*fYRQ/vuD%$0(XO+vlX/2buVS3L#####-S>#KS/b*2phT.^^A@#F6Eu.DlfLgO]Bb.XW;#v])Z3#g2Ix0g($HN'X65N2M6##:Fk]#>'U%189/W7OiU;$\"\n    \"(,,##@]]&#Z#+iCE&D$^lR=F3w_]9MsfLU`3[4nahPWS<C&L=QE7h>$gt=`oi>kJ-B>pV-kkin<U5F:V945b#lwpk.@jxW7=Y2I.r6[c;$L$B#Qr7/?vGf.?eU<K3^c*,#6CIw#Vf1$#\"\n    \":88d/$4Og*%=)gLnxAV-,wxj-_6SqpPp<V7LC#hL`C6##'C`b.TurjV't7v&l6*$@r(tI3i=tA[7&+/[N+/?;$/C20$MD>#@O1).sudmMGmRv$,Pl>#/V1v#;Dwo%-qC?%%Lb?Km5-Q/\"\n    \"<L[<$8o&B-M/5R*7<eu1?tr*.EL;Q(]JD&=#qJe$?Z:l0d>vw$PHF:.9EsI3>iJGMV?BsMY+M4fg,7>;xSPwT(Qf@tC;9/:LLpM1hbtM(^3N+`uCpO]n]1bI(Eou,kI529IS#v#5FNP&\"\n    \"h`Rp0:x_v#'mD*eRMlY#0rC$#W@]v7lh?lL6_9,NQ2aBU$TpN#p';pMqqJfLbe*$#-dR)$Z(V$#`9F&#=Ja)#&[%-#?rQ.#)N_V%IKe8@Q[Iw#R/)k'+;>##?Y:@#6H#^=M[[w#'.ZQ8\"\n    \"7S:v#1/L<$4L82'`W2i<^#xh2K<AA,EY,##*ZQ=Abo/U9B]k/<X(@=7:=tT/q*Y/2HT=>-8x9f)&(H_+Ahfi'Gx@@>k@hXQ]aEZ61L9T&_A</6WV6<.rJWJ6=c4&+Pp0v-SQo],w5Q7&\"\n    \"d:gF*0$4w[`@o0#XhBU)2BvR&L6^6&[uXr-QYDp/Ng'v-?BAT&L1#/Ce<)S'J<DH6LZnbinq2u7GBbI3:NYg*Ab'9.(6g:H.9i_,P_i],GeBoe`f#5SbQsr$F;3:M[a)*4/Ur.QGB'kN\"\n    \"na)'5O=ml/8P0f)ip>V/kXIPQ@jZCY,+$3E^E?9/F5YY#)0up8^7fp&g####Ks3g&',:8.gUs`uuR_+i-@-b[1v.U&l1(58RXe>#*8,##.KCV?B1.s$=C<T%4QM,#w&/gLVkFT%1jpo%\"\n    \"<K0E<n2'?-9rOM(6scg)6>8L(i*?,GlR?x69B7g)HLuZ%eT/i)<=6g)'wZ)45hN-*TV)B#9H*C+[pc)M]rU]=fuhB#sQQ$8SW1#.<W7m0DtBtBJ<B-lLkf$MObI$v/MpkLlIF/MF)E?#\"\n    \"C^8P<Z-3?#2cC;$3jhV?Q/KT&9]WP&q76L-uFkm$0fF,M]XY&#Blg<M]Q4I)186L-n4'WML^R#1=J&v5'^Bv-+EsI3KuhH3HAMD3IOFM(ETs0#/SY_+H9&`j/d`mLJ.;5SpA5U(o0AkC\"\n    \"wv](+;*s0CJ]RqC(OF$K^/5##[Cqf#J0U'#>F.%#J,qT%PCvl/@iBTTs[0^+6ax9.Tm1T/5d_s-/omd5Smj`5<1k:8r2(j0-%nK#1s-Yu$Us`u;S8Hg0gw#MAF$l$Ig55&rt)R<n9F9%\"\n    \"s>rX/UxWD#u?lD#(e+H(MHlD#7%x[-3+gm0_9hP>Hrq;eaBFX7@'BR/?QOB20Oe68C=/R/`GEvEG(1-@42Qk0v94M04E&O(dv$BPB.6V3Vk^HdnPOV-i7TP8C`@-d_wFQ#xFwm0jn0N(\"\n    \"LUaJ1J:)iu(I.m/nrducScFe-$I9D3vfF/21k`s%8N$0%_wPg1pjxw#.&Es%T>$_u95VT#`Dl>#&1v7$3%-iglMjI#Mn>3#xp(G#g>%@#?%ffLn1$X0;.=`#veJE#_YCqL+-g%#F$8nL\"\n    \"%M>gLj[)Z#*_uc+'U;8.)$o_Yn-&fuPUpA8la`Fi2_mbimS#oL3T-N:e1OA+IKru,6lju5r-)q4_*@g)(Mwm0UH:a#ae_F*stC.3xE6^4@V*w$C]R_#R(1+*Q(7]6L77<.hHK:%BJ^P:\"\n    \"M;>F+JCce)m.4J2>tWU.,eh80(%Ki1`4D;$dHMd2dPh;.bb<w-]SUZ-shmY#&2W4'dDVk'&=-g)JGdG*(fS5'?T97/t7+i(H`^F*VUE(&PkwjkekAM'xIqc;NpxjkvuKd498Uv-*iqP'\"\n    \"LUZ((KK:a#@)s+PGkNp%ST(K(:>`KiU1[K)M/B<7[9GRCk2YO0xXV+5mgShCBRFR0WxA-=XJ,##1q2`#EE'VmK/(&=&;ju5X^00.GAYY#t<X)<)+xP'I#jm$FF$<%;W,)<cZCo*KJXp'\"\n    \"(7'U/e#5B,tXmR(un&60c<*H*tmFX$77@^5uRNX.U8-W.oB:V%I[mC+Y(m>#Zi-51@0/a+&L;A5XjB;.:-bu-[Vo]5QEOY-_SGB,%%ZhLGB?>#Vl24Dl#'%#>6S?##SrB#s`%E37jt-$\"\n    \"(LM8.mDsI3_+xC#0[0@Jbx-`Y9vMbQO,0fa3`(SmT_idu5-7LCE[AuuMW4oLJ[]w#'bft'mA5&#+[E.DjriW%B?@W$%P*n0s'Y>-UBIv$G)C<.,j?S@4O7>%StVV$67RS%B3`v##Jwm0\"\n    \"(KD,):K_#$;<<D#iWB1FoB1r:4?Yb5N#BSR;'TY>w&DuY_G[e$0_M<%6h_V$>Frj2*obA#1qM[$'H@D$v=xs'_Yvo%M5DX(vTuJ]o1IF%*WCxu14.[#KL17#-Yu##UE31#J&###F,HM'\"\n    \"hw&mB:=,&ueGMfLYZ7fMea7DENBZ]+tCF&#N)[ihN4RMLg$C2:`uUk+TxD_&e$s-$Xa=.$$%/F%qFm-$*c;&5Ne1p/KnL50P^A,3J'I21?wdw'<wdw'N@t9)k)/m0B4i-6K^G_&-(n-$\"\n    \"ZAu`4-?rV.iOJ88RWaJ2XPq]5Rpxc3S#>)4p.VA5_oQ>6DFP8/l/fM13ls-$PC-j12APk4iN_w0k88_J>@Lk+:Nk-$n-lk4Zs0F%ej6F%]ifiB_idw'@i*.?*/EkF:JK21kg*:)V]?kO\"\n    \"L;w9)3DO_&@xSkkI:oV7^*U;.BY9R3;,D_&(nj-$4<k-$D<5Ra5X/F%pEs-$$Zk]>`J><-1kBK-=M#<-g7T;-`5T;-06T;-?5T;-A6T;-@Z(*%Zr-F%L/l-$*j^w^uk.F%)sp-$&jp-$\"\n    \"'Pc_8NO3F%Z[r-$fIQF.oheG*;p,g)<Sw],U5u`4B4pV.Q]<#-u*K88`>p;-ef#<-v-R^OA*@q7Jn1p/ZO^F%1V,RsMJ-F%>jcG*et:_Jt.X&H5u#<-g-n6%?KjDNk_;u7eNYF%WLX>-\"\n    \"4C%^Ou`5oLgno4QYLI*NSJlDNlJT,MahDu7jf(G%_qt9)'kj-$-4U_&VY#WoS$U,M]7QA%qW+?I`Bj.Ne9$<-C6s'%->wEn(.=:2)H'd3(MV8RSOQ-N,9$<-`rA@RomKDMjnS/NC>T,M\"\n    \"<jK,N6IuPSb2gw'O[vV%rqm;-bWCx$EC%<-R>5lO^TiH-^9x/MtrPoLgcm)Mqa;xL_IBvL$M%2N:EK887g%RNL`D_&[hPG%-a>&5Okt-$?x2F%n6$j:;:B.$&CF_&XH_]PTpo;-CGY)%\"\n    \"fjm2`M1$-NF.94MA:xiLtkiU8/9`D+l9_M:*[7p&b:G,MG/M1NUuj;9l-.<]J4$##RV`S%XZPrZ8IZ`EdRqf:HXcrZ'L0g(5/0)EN`dfUHAvM'5RXMK_`1T%latfUu=%H2qJ+m]Z6QGr\"\n    \"0/@a3I@nYlRnCgChQX;m.Y+<6idMsZoF@6&%UGT@uJo5]2@mm8LZxZ#h2mmJxEn)jDExg:XLbaW@22<mn<W6/Cs.nA4JJNp3M?$GeMG[#vO,bNZ#p$#+h1U@I6C$cVc`$>EOsH`:@HU7\"\n    \"N#:URcg3bsmC<C=bs(Cbgbtt?fi86&Lh5?*]qe1*w3I`*$X_$+vc8m*L839+.VY3+twaA+0U7P+tQ`W+TR^^+S%#j+94w<,Hr0V,AKmG,9S&Q,Zjr[,Ovep,181$-_:j1-Hwl;-G>JE-\"\n    \"5r)p-m?T^-1Ruj-u+:v-k]e1._jI9.dILC.#g^j.Y11_.%gg//o>Mw.IP@5/Mcb>/`jEI//PHS/&UW]/jJ[10Octu/Iw?)0qCH40u,[D0@?[h0Cc0V0`],c0=OAm0XS%x0H+?01E_?@1\"\n    \":WEe1C%qR1])^#2XWCk18i7&2[5@12/RH<2kZ+J2944#3koWi2?9at2]72)34Se53]7;D3jm=N3GWZw3lmFj3'(F:4CUV-4Q^f64DJYZ4CIMH4K^oQ4LoCw4fT=f4S,Yn4XUR=5&;w-5\"\n    \"rJJU5)%2D5E,lN5+)<]5TN)p5MM&#6Z-)-6e)&66lLY?61^OJ6PInp6`/h_6x*9j6pqLw65QO+78o6P7<]kF7HbWm74E%a7i#Z488.5$8XA+/8fL:88#EbB8J$Bj8BR([8Rs[e8fq-p8\"\n    \"9i)&9qL+393+WA9m#2h9#v#[921N*:30Bn9?uVx9aauG:IHp3:c9[9:(Cl?:k/`d:$::S:org_:Iuqw:9f2&;,J`1;H)b>;UrKG;^#2L;Ks-X;`VYg;gQWm;Q:@8N;Ce3#QlRfLm?Q.#\"\n    \"4Nc##rAP##OvK'#KS3rL>DmB&u,+,M.Y5;-bNrdbR8RtLYa`m$PoQS%EU^R*MM:;$AVm_&cZZ`*Ecm_&XO/2'^Un_&+QC_&5(o_&,TC_&BOo_&)@=G2/wo_&ZINP&`]q_&[LNP&kxh_&\"\n    \"$Vdl/vCi_&n2<A+Hhj_&?+5R*,bk_&4mC_&T/m_&`FRS%^Rn_&]%;;$we/ed)SFgL8q2?#7B`T.6@@[#?B`T./fLZ#OB`T.XVd_#WB`T.D0bx#-rG<-+fG<-GrG<-,fG<-f@`T.8,4*$\"\n    \"*A`T.Dn<x#1tG<-/fG<-KB`T.+wL($bB`T.h+j@$[@`T./*iC$6sG<-F_:EN=Fa$#kIk(N99aP(AHuJ(MhW?-;3IL29Beh2EqRxIxarTC%hitBhxtLFu*cM:C10@-b-%F-$WA>BdH`9C\"\n    \"'ditBBjerL:vAeGl#oUCTe0@-T1D5B`EQ@-8q5)F2AhoD:H*vH3i7FH>P%l=*T1O=2oLnB1uwiC=n5)F5U%F-&p>hF)s8oDw?vsBQZ=lEnrCkLeE+)>W^:(6djeM1V#f%'#;1eG38vLF\"\n    \"+YD'PSO,-MXmSE-%O;9CuicdG/iCrCgHaE=kW_J;f<ZWB1FuC&E3FGH,C%12p7-02mH7UCa_6B$.E$6T^JvDPdn0T&wj9'#ZqB'#vP?(#N/B;-Urls-aJ#lLfYw+#cst.#L*]-#P)1/#\"\n    \"'6[qL;KG&#wX@U.[5C/#]RFv-^S3rL]1CkLxf>oLN(8qL.fipL(FD/#<MM=-?5)=-<>DX-J,Ok4T-x?0J)@X(V3Mk+%$Kq;6tF_&6Cn-$^Q+F7JERfCS0K5BETfu-1G<RMXoUH-BZ5<-\"\n    \"w%kB-VqX?-Wr@u-.#krLUit(R/g9kND3CkLlf=rLN4oiLAf=rL`3oiL.P#<-e&@A-5u&4MGJr'#$Z5<-9bDE-KOl0.MJMmLrRxqLv$](#V8q,+8[=)#&=M,#nUG+#<^(@-B=]$Q-%s=-\"\n    \"`eQT-StL1..T3rLqC@;T@bIr7dg@5B0'n]G+tB2C3l4)FAdw]G$#w9)o3=-m8&/kXdYH?-Q&@A-wp-A-Y+KZ.<tI-#I##xRnR,.#?NYS.#-3)#mSoo7c`X/2pU<e?+ZCk=m]2R3/6KQ]\"\n    \")qOUf(x5x7jP'99MuuD%mb60#w;-e%7('i#d]O.#&25##C8B:[52np712A5#KA*1#?X#3#=N<1#=lj1#kv%5#w9>##^?G##:F^2#`5s<#:cjL#]_^:#_4m3#o@/=#eG8=#t8J5#`+78#\"\n    \"4uI-#m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#\"\n    \"%/e0#TmD<#;Uu>#4`1?#8lC?#,px=#0%V?#1/PY#3.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#7QJ=#;0=A#a9OA#eEbA#iQtA#m^0B#qjBB#tm9'#&)_B#%3qB#)?-C#-K?C#1WQC#\"\n    \"5ddC#:x,;#>rvC#=&3D#A2ED#E>WD#IJjD#MV&E#Qc8E#lIf5#ppJE#Y%^E#^1pE#b=,F#jdf=#Z0?;#VK>F#jUPF#nbcF#rnuF#v$2G#$1DG#(=VG#,IiG#0U%H#4b7H#8nIH#@@:R#\"\n    \">*fH#A-]-#GBZ;#1=+I#HH=I#e;':#6OB:#3[T:#3C0:#nL4.#Z_,3#+[XI#RgkI#Vs'J#Z):J#GVx5#8pF6#Joq7#8j=6#l5n0#nSE1#@%.8#LPC7#T6LJ##rs1#VqG3#WrM<#[@T2#\"\n    \"hji4#GLg2#t4(R#E9P>#m.jD%KGRR2q^);&6JrEH381SDkoH&Fu@ViFv.1VC(3f:C$]eFHpg`9C]&77*25emMDbCp7)`I'Iu)IQMEkLp7-2vLF]Ta2B5$89&Y_nFHR/0I6:fsjNEn?m8\"\n    \"o)<e?4D*nMM^kpB0,DEHeGcn<m?+0N5C4nMAqZ29(/Kv$4W5W-@CQ@9<r/kNEwd29?xg;%6a>W-M;Ve?3R&+%up9-OgkBkNQasj9&5H1Fs86h--^U%'MXsTBdAYGD'7d;%ALRe-vmJF%\"\n    \"nBoNM8c.dD+=d;%+s4c-vmJF%vs0hNG:NJ:Cc#4EZGmL>FXGLOTpoG;'+OGH*mWRMM)PH;JQAp&sa=KM#)+aE(xg>$tpia-pH3I$tjbkMw$1oM[;@IOF^BBF6FHv$O/R]-xm&+%XZHHF\"\n    \"brlKFgtkkM4J0^F,7Hv$=j[m-#q&+%m)VOD%Lv<B:>-lE&cS>'LAvW-q,k0GA:9SMS`HB=ECDp&M8mW-q,k0GBCToMwxuOMAg>vG5'&X%O9`9CrdM=B.Hpb%$9ClMc?LSMRP6#>^sKG$\"\n    \"F/7m/]@poD`?b'%DW5W-^dDeZFXpoMQVd>>(0Nv$J8.Q/Y4^oDtFoVH/q[5'<$mO-RAvW-nkiAZq()WH=W=U&e%VeG%^4rC#8A^&P)H<-2)H<-R/dW-x<X0cIk,TMYFfs?+ZKW-:#dC&\"\n    \":3Ux7eu@p&ToeQ/x':oDM.wt7xT(:8>#8kEV+Gv>*G%'I6c,pM%;DPMr5V8I76Jt%X^IUC-mgoDI(dPNW%&W?kO$sI'Ip9;XdZL27II29*HLc$LXvlEr7999twp?H*p_aH.HXnD3qMfL\"\n    \"JF-##$)>>#K3w>P;@e3#cOj-$&t9'#vdlb#O'>uut8X$Mws4U%,q+/1fdfpC.w4/1#KTV[>b*N$X(+N$=ut`-c`pCOG)=s<H-^V[MJ->-C6n'&8ap`?D?839m7T)096AT&j]+Z2TZaJ2\"\n    \"bg/eaR4wiCes`@BNGZa<<$2R3W9Vk+/Tl'&[.n'&dSng+:pq`?pgfi0T<pV[1eXSC_#vW[IVoiLaF7p.lYJk4jAXC?>]f88?`f88/tqY?cWUT1&ul<.&1>?-K%mMBx'v3+]3S?#HVxiL\"\n    \"`EBB-0_3uL-;5Z2)[S4=Gs2f+3QUD?=5Ok+1KtC?Nx%a+UG27E6K)N$Jk2Q8XO`Y#_0>?83C(gLq.h88mTg5#EmM^[I@'_[%TX0G)woM03?c/1-5)E/1u99_b`qpL,p#-.KU=5Ma1tv8\"\n    \"e<`;%LBi'#+WIg%xLJE-xZa5Bc>l[MV.X]+c,Oq22`$V[Q<j2/uI,<.53AI661/t[#aLZ[L$ZQ1670kL1-Y>-krcm:'$VC?JR#<.$]#H&&HSD=2hV8&[sEN1*op?-`xGqVwUhHQ?'&RE\"\n    \"K-WQ89*A%B,h_gLTrtW[Oeh*>5o.?#@B#W[1f&WI9dC01d'@5;1Y`X-Nh5R*GIGR*9@/t[s19E>EE2n&BN1X1KNlj0q@HP8=`x88f%9I$)w/I$eY3)*E+?']Ujmx[sqdsA?fx881(8/M\"\n    \"E@BN0v0,O4FP%a+(^s63$wn5BBMXV.$xDQ8%kUL.()Jm#wHsW-/54K<tDq5#HAGp8tI:Z[ko?Q#ttdsAQP9a'%B/[$k4G,#Erf88BTtKG*aV3'/f1$#=;B%BhD8j02g7b+'#vW[YSdT/\"\n    \":BtW[h26Q#7Q0N(1=(,M62v01c.5F%7R/t[*lu8.pVMj$;vGg)5UL,M:JD11g:5F%;_/t[.lu8.x%f,&BV%*+3BYj0J[abJ[0,_JZ-,_J]3,_J?M@&,VC9F%_9,_JA`w],VC9F%a?,_J\"\n    \"CrW>-VC9F%cE,_JE.9v-VC9F%eK,_JQ'vW.]&QY[c7vW[?F(tq*ZIE-pr@['=&Im#3C/F%W7=Q0H)rG/PFbm0P)lN1Gqq?-A]1s7-9?<.Umu>-Mg18UPaFY--<R)0Uc;N0hA6d/jPnc)\"\n    \"i/+jLpr,t73-@P+hxq?-S=Af.+6/S[IdMj(wgfi0=Y#.MtS%)*[;w0#ENh>.8AnB#O5`P-Lmm*MmfC12x@HP8EktW[m89I*lrJ#2lYnV[M0'qL>-)41BG$)*bf-@->u68.==*p.t2Gx9\"\n    \"h:_5B+ktpLK&-Q#jh^#2NYWI)'BOK2lS*)**SEjLLYDm0J])q0em-=.*$GGOB.)g2bhb>-nQ=v-%=ufL]hev6ONjj<7C4g7-#fm#,7%a+W+$$$qi-<8uG@g%>^3uLVPq%/HsD^[fL>9'\"\n    \",JJE-DCU694gd_#N3nB.&0*9B6bQ][:+xg+5.JpAUC3p.hBB5Bg]IW[b7)Q9PW(;.n.fP9[Jn*%cg-R<%2;nN>dc<.Or)pA<$qV[1uipL8mToL#gipLje'KMU#`5/^>1a+Jx3/OB]mS1\"\n    \"8SkW[$HX>-uWa5/=JHp.=m@P1LM-7*xN*9.%.fu-V''nL-t]5BgV#d3XO>na43l<UQ/mx=[9S>6[v[.M'EYcMGnow7:R5s.SHdM:x8Ks-0oMs7;?69KeMKs78DpTVX[_846ljS8-75?-\"\n    \"`^+pA:cT18MW1E4lC+j1'G2q14PXD-C2Dt[4$lk0lQ=fN5PneOu&uCPIbo(P%w-51oIhWRbE751fGWEOP&QY[mP(HO6TUs.Ifim1Q%DwKua&<A#FmA%Aw`29[s#?6x&W&5Zk8?6c94<$\"\n    \"tV#HXt6N@0G-w;JAtGm#s-kpLr>T>.c^b>-$ldm%E]72NT:R51qZ?t72+3v6>o/Z-8tsr$B@etqM*)tq5`t8T^2$6#NYWI)AcjA1lj4g7:R#t7WCD>#(p.^1.bg88]@QkLeZWmL(BB49\"\n    \"`f-@-#[a5B@,@U2Lm@g%'p1d8rAhD9W=)##`S,<-jS,<-(r(9.J9?Q#wNC2:CHNX()Q3O+Y+vlL30BnL%+p+Mo5KnLH:)=-)2#HM$B^nLB53>57g<,<$]bA#tsVG<U)OX(tnIb%*K8)=\"\n    \"6:P&#$Lx>-vS,<-%V,<-BIrIM+mGoL6:)=-6u@Y-]+(F.$+Jb%%0Pb%7&4O+15L>?CHNX(9,4O+VoYlLC;)pL%+p+M)A2pLH:)=-92#HM6Lv81X4LmC-]i5M7@$T4V*bSA^Gu`43(JpA\"\n    \"lS*)*E8[V[c1M9.?G(W3[9^PBeQHX14hx'&sP+I-5kx'&Y^uMCh?xeNW7]6MS&c?-F5g,MZL4RM]nHlLf?8:1gvr[0=<l$'^,RGE_'C[0=-#(&`9Md2C:bW[D@f2$lwu`[AqKO1otq+;\"\n    \"LmLV=/JM>#x+?h%9fSiBn$@8.>1R8.K3P49YNIh,V2S4;2ZR%@&g6c+aq-vA4rkL>7,AV%e.Jm#H1Pd&]'89]gj/I$3?0I$W<:>]HBw29#;l)'dwrs[vV_v[x7@4=J3:gN6%]v#nlp/M\"\n    \"eYrN$,7Dt-DLwoL]VvQ#^W,N$hYV##$gOFD4'<4#\";\n\nconst char* GetDefaultCompressedFontDataTTFBase85(void)\n{\n    return ttf_compressed_data_base85;\n}\n"
  },
  {
    "path": "src/forkawesome.h",
    "content": "// File: 'forkawesome-webfont.ttf' (218132 bytes)\n// Exported using binary_to_compressed_c.cpp\n#pragma once\n\nstatic const char forkawesome_compressed_data_base85[214910+1] =\n    \"7])#######91@P)'/###[),##0rC$#Q6>##T@;*>[VPlmI$g]=5g>11gZn42d%&XpG,>>#I&g<6aNV=BmXpxb-OJM'^5YY#D2XGH-VSA$NiFJ(LjK8/d_(*Hlme+M:6h]=3YN$5#-0%J\"\n    \"a+msP.*8>,rM/m&0.d<BHk.w%%s.>-Q@pV-TT$=(^K-G&WbDE-FqEn/<_[FHv'=gu;?^01=<jl&83JuBQ:8>G#cDE-BqEn/DJ[^I&IP+%u3S>-kfWX%34^=BUkAr'X>wu#jx###^bCiF\"\n    \"cLV%%&>%v#q,'##$rvQjQ&###(Df$SodPirc[4gL)>$##4+0oQ87,F%t$pOoE7np%xF[w'OMYY#N$H&#4$aw$E5x-##C>uumwmo%L0vhLEAgV-04FX(r#?v$-d8KMW=6##R9dA#cC&W7\"\n    \".ALe$OG:;$c7(;Q^5Gb%hXjrm(J8Dt.4r5/1_FV?w,QfLblMv#BCkh#0:-eM@m-^4.,<6Cor8;-'j]##p+@cV,&6MTO->>#MkKI$k7?>#A2nu5+x0^#$g(T.G[qr$rVjfL-:K/LW:4gL\"\n    \"&8T;-::#-M$C>,MLtUaNq9N$#NOuwLje`=-g1ukL(C>,MPZH'vbVC_&P(A&,gJ+x'jbE.-6O_>$fH[caHwC#$Pj&:).OvV%,FQZ$le68%SI4v-Ji*gL4@,gL9kL)NF;#gL'=5,M/.G(N\"\n    \"?mL)N_,Q)NW)ukLOS#<-]UhlL6(0jKQ0E:))3,F%SYY##iCs9)?EMb%vSAR3Ha8xt3G###<wvuPijm<-hQ'DMdr[)*EJn-$JYd9D3IQ;#*kBwKb5jVRx7Zd++:#gLa7kJ/;aP5J_-dAO\"\n    \"[,l?-owsnL,D;:%AiL#?V@t(N_UUp7Kpd-HApUEn3x2F7>eL#$&cPhLrwl;-&:e;-TpiiL]5]jLPRmuu8l5.?pF$##CYek4#fJ_/&sMkF)fkxu/I>HM@I5**?rsfDXhCZ$vW3_NNOP,M\"\n    \"s5v5M_V=5]kik##dn^k+o[h/#bL6.NFE:@-_3nMMkr-A-NLx>-d1G?-HpI3%uZnVo#(^fLq:T;-h:t$%OmK.ZfNkd++F5gLV%0/LoT).-k_G,MRIpL8?%$Z$T^S2`(@,gL-F5gLGVG-M\"\n    \"cY[r7M;Q9i,TC_&q4)9.B@uu#[edum2fj-$:%K*#UTj-$12*x'46nwB&*,F%t3@kt,TC_&J2,'$6@2X--0F.vg5Jv$V/;.MiE;/#(aNjL]XAV/Nv[@tQDtXuOfO,MC%*/UQuefLjJ)G`\"\n    \"xi&&t$vS]tSe4-veo5R*22@qL#YhlL(Nx,v0)S)v6^?UP?A,gL?:#gL_3YSn&:e;-<Xu)N3Fl(NUUZ##9otrRPMb2iIu9xtxPs[t4q=K3ZD/Gr#s]xt#RodWKfnfL)M(Z#R++gLQF5gL\"\n    \"S>45]k8L_8oHj9;U.l%l2fj-$OOo1vqCpV-e1(F.dc1T.H0*##IGu[MlK&c$m]sVPEa:)N_?;G`:OC^#M`[FMiX^@%=uNrLUKx>-'SP8.oIh7%x8v-$4.<c8qv#Z$.7_>$=tmv$'L_r$\"\n    \"T&vhLL@,gLPApJLSlc;-A<oY-F&[Ee#VA`Jqg+s@5C_>$5Y#W%,Idv$#;U7%-Tt;-Rcb4%+9,F%GZNjL)V`=OM0oJMu4$###[@V'1&[w';7Lk+*eu2;'Lu(N*L>gLR5l?-T)oJM-+?%N\"\n    \"cL>gLEUqP8Wq^>$/X;s%WCV2`mD=5]]bE_8Z@Ok4B9icj`#3xBj8'##9b%Y-?v0F%kv]kFM;>uus7T;-%ji].VH:;$&3q5'Mhkk0Q[gFrbw$##&hV=u9I=>Z3iI9i<-j8vsXQ-HJ5a/$\"\n    \"2=6;#Zdj-$h24K3;ICp7_3Hv$2N5O-AvtsNb`./MKc+p7o]L_&6_v;#t?Lk+`3hW/<C>HM_3'D&Co:_A=eU_&h.7Q/*iQS%XRUV$6WIk=*:Z;%c5/?$K*:7%MDUk+Rod--U;>uuLBw,v\"\n    \"%A>uu6HDiL*9o,v2SM2iQ>:@-PZCx$TW):M0aEO8S-h-6T8K&>k@d-H2Gk&-24pfL5AC580GwctfibKMcQN;&O(r<-k;Kw%JZF_/RWe;%M8;.M>VRFNU9[A4@NR_8SO)##?F=F.?HW@t\"\n    \"=5b,MdFY9#E:L+v2M`f8Ltvd+>q.>-I+iE%x&&Rs,udR*1=:K<A'JY-;sARE36F$M0#e.%MlC<-qUL.Q'q)?#V@FgLf@o`aQk%N0,nHS[V4+gLhZjO9N'^&Zv.M8I?k-Z$cPo'.P%+gL\"\n    \"vrU)NIg2vuYm.gL.a92^pBJ2LdN+Ra%BL_&`Y&FI;E:`&]m@v$<k-Z$q2q5'#A06vi`Nd=9csbMZX1I&Eci:Og>m9%5Ii>R<ICp7xKvV%SMb;%)o'^#nQ.W%FfG<-R#iH-xL#<-#Y[^M\"\n    \"8@o79vJQZ$&SUV$/XkV.SJ_r$mhG<-kXjfL]<_]X,kqVZ4f_G3NZ,8fK'cWo,5<+MDI-#YMx<gLJ_3m/pOHU&?EFvG&&a5A&Gl##dK@F.IUG.qa#+##Ai5uuk/AxtNHKW8)RGgL[oX%(\"\n    \"p(>.?G@*R<>@Kk48/J.qH,'##V]'##,'LKEN(Ui9Vb-Z$%<J$&Hb^sL/<Y(NFaVg(ZamwBQiQS%(>uu#88H`-+B=_/?Rbw'FruXu%Ie2M)1K/L/>`#6OsnfhN?D_&Jm2Aur/(&YF'%Z$\"\n    \"^K-Aur?L&#V08K<A&3/qbtHYm9JjAP$4G>Y%_N68p9Xa&l2D*MdZQhM&0k20vdsD<IU%d3&,TZ$:M6o%qs.>-^N.U.hndo%`O#<-U7T;-g?%'M*vv##t'cYYV%e--3,[w'oYJv$8m*J-\"\n    \"g8ggLiCg;-#G5s-nlRfLMC?>#x6FGMm8#&#[97#Mi*qRDigWV$lh5;-1^2t,<KNB<'#bZFhOtsPR'16[10CNf(,VgpiR;h':#<t,t:N67_haNAI?tgK4m0*V]E:6[?ZLNf*2`gpkXDh'\"\n    \"Tw2e1@WaB<+/tZFl[0tPU*(qZAaUNf7F>?t4D7kAm7$LGa#&2qk)@0qgKJ5qacn8qK$<<q6;`?qwQ-CqbiPFqM-uIq/gNLqWL)OqBdLRq-%qUqn;>YqQ(x[q#_H_qdulbqO9:fq:Sgiq\"\n    \"$e+mqe%OpqO<ssq:S@wq%kd$rf+2(r5$txumiGG(JKG/(C0gi'@-p.(<w].(8kJ.((lv,(n_d,(jRQ,(e@6,(`4$,([(h+(WrT+(SfB+(NS'+(IGk*(E;X*(A/F*(<s**(5ae)(1TR)(\"\n    \"-H@)()<.)(#*i((usU((`.M7#`e_2nNq%s$@Xq@/&)###^$v=P0+lo7d<GV)df&3.X4T4NG1moL2ulS.6.>>#cYlS.?7YY#r).m/#Auu#JH:;$Jq]G2TZqr$%d68%7lQS%pvmo%%XjfL\"\n    \"DXPgLiuv#>]XbgLV)GT[l2=<Q[J+0haq0hL:'2hLB;m01REU<dc'ChLb9MhL%=G=$9Zw<Zaaxn/E*:kFmS8-#w'F)#JnFk4^DK=#.rZ3#4qkrLduM7#9WQ+#.X5R*;Qk-$e#w+#,:t9)\"\n    \"U0Mk+@F(:#Oe/R3bm3<#mv70#^nP.#kdi/#t<Ak=O8u1#AhR-HTQ@;#pUh9;3g8_8eqR-Hng,_J&40R3DpG&#/8P1#1V-F%uQt4#FdMk+Sx;pLraP[.1h*##SHvD-C86L-Q0QD-gqEn/\"\n    \"l^&##w**##wY@Q-a4`T.Si(##1a$]-u&1F%7N+##@^BK-JRGw.Xs+##wdo-$]]q]5SYm#6>B.;6)PP8.oLIV6a7Wv6<_*87G=S;7w$kV7,GnV7FE1s7N^1s7kdP88il%98]-BP8lVjfL\"\n    \"@4nAm?U`mLVhjmLlnJgsF:Xgj0p;*G2(W*,Dt7nLq(mZeE$AnLH6KnLmR`[.H6]nLEHfhE2nQha1`hO)Bd4R*hYtjt^RQw9NpHk4VcxE77#a*#Jh0kX2i*kbpsZ9#oIg--NW1R3n^+R<\"\n    \"hlU%#mx;*#T5Ck=m*u7#IJF/#3KWkLt*59#7-;-#'2mEI*Z*:#E:#F7dQ`-#<,2R3+nH-Z2F='#kKw1#@J>$#&O+kb+ZCk=K&U-HA@R1#4Qs=#dh_0#3VmEIsJY:(LSKR`63/l<#/nF6\"\n    \"DV2`@,&GxSMMb:_1N_:qoqarL(.lrLW/lrL8oRG?t99sLQO8/lu?BsL9LCsLfp-TMwKTsLO`_sL0fhsL&FHms$_psLUv-tL$w-tLC(qa[(w>tLl,@tLI5ItLe9RtLP@[tLxDetL@x]$p\"\n    \"Q)rnW0Q2uL+d<uLniEuL0jEuLDqNuLpuWuLMt/cn5p`uLi%buL=(buLi%buL>.kuLO-kuL4,kuL03tuLF1Qce8,&vLc?0vLNc[25B'Lp3Y4Z9MXWK&#Oil2#Tr'RE^3<0#:%.R<'RQk+\"\n    \"gL^9#8$n/#c&j--i`d'#MwBgLu;]0#tZM9ihxJ-Zb@U.#*ib-#bU;3#1*f$#$ZHwK;8,=#F1m9;vecE[=f]Ee?qoEITj:6#J;YnL.B@;#_G7_Arn99#+uZw0&'vE@_wiER`$jERX9Lk4\"\n    \"j3%/#IsBwTw<Fk=[BLk4N#IwKajd-6BA^<#11[w0rMZ9V,4dE[[*5R3SE#5#ji7_AbO:kOfqM##ShF8#PRx7#rDigL+/u1#egFk=?H=w^q./7#YMCwTno`6#V,,_SdvN9iiL#RNwB2.#\"\n    \"IO#RNg5H5#ahUw9L<$:)@vvE@]n^Ee5]sQWQYmQadJ2_JQII2#OK[kLrm,D-FJvD-GO#<-;W^C-XZ`=-2.Zd.10%##gYkV.A_(##QvfN-&r-A-c+MP-6sdT-e0PG-ZB;=-<F)e.S/&##\"\n    \")m*J-w64R-[I+_.AH%##h+MP-w(l?-K4>o.2l'##qf^o/[9)##mj)##gZ`=-Hf=00(=$##B8+##KRZL--A:@-8*LS-'gF?-&bCH-hPq)08^*##5Q*##%DrP-m=8F-%6S>-.gF?-qB;=-\"\n    \"b2QD-/Nx>-X?9C-YK,[.m%###))7./v=###<+m-$5)<-s/3eCs#=*`suFE%t65T;-vZlS.qPa@to5T;-qQP8.nY&]t*SJ`t5k?Cu*;cY#sE(v#_OC;$dX_V$<b$s$vuhP/(l?8%[sZS%\"\n    \"KmsW%t'wo%j/<5&>(.m/sBsl&USSM'GVjfL=w(hLbsKn/_Y=0hahX0Ld*ChLh:.UR*$x0:VnTw0s0g5#XtC/#M.,.#IjY6#tct1#xQcgLbbEB-B%Vp.^3E>#VYl-$YLD>#tpE>#;pF>#\"\n    \"vI8r//C@>#>rC>#Wq.>-OG+_.i7?>#S;8F-JM#<-LHvD-(p-A-%W_@-=86L-I7Af.$NB>#bX`=-oKx>-9cEB-rY@Q-GPZL-+oYH0s'E>#iZA>#7Ym-$J4D>#[gk-$0?F>#7k*J-qg(P-\"\n    \"dr:T.nNA>#?-OJ-cYlS.Du?>#eM#<-/`CH-P=Ps/g(D>#WMC>#OcEB-_ure.m,>>#i5T;-H&wX.gfC>#A:7I-1;C`.&E>>#4/PG-(#Mi34j>>#gWF>#(CA>#8rD>#hO@>#8N&C1lYC>#\"\n    \"^+@>#fAC>#=@FV.$u@>#eo8Z.I6B>#8aO_.<^>>#:aO_.Z]?>#U?:@-R3_W.HtA>#'%v[.di?>#5ZlS.%LF>#@+Yg.PfD>#op-A-5j)M-B]AN-<1QD-ceF?-Gs:T.d4E>#CIvD-<j)M-\"\n    \"_4S>-bGuG-Jn7^.cv>>#vpDq/$fE>#?]@>#Nn7^.M+A>#QgG<-dr.>-SbDE--)LS-M6T;-X+Yg.OqF>#n4S>-A&kB-jm+G-rBrP-MV^C-_s:T.dAD>#kt2B1YsC>#Wi@>#5Q?>#CRgc.\"\n    \"sYD>#'Jbr.<[B>#fhk-$9=Z5TOF5MT&g=mTvXl.Uk8kiUE2Y/Vs&.GVLW=KVf1IcV6:e(W$6T,W]B*DW.YmGWDLE`W/^,)Xg]CDXBLa`X92d`X(Xx%Yh#L&Y%$#>Y-$cAYc->YY4dvV[\"\n    \"6lQo[X3_8]](3P]=1TS]dSno]q$lo]U.05^S*65^_h>Q^LB/M^xMJi^,p*2_<J+2_H,oM_wiFf_YmR/`I$(G`fE.g`l6_(a#&,,a(GlGa]I?`a;*&)bPpADbu;t%c;Z0Bc+)8Yc/3Suc\"\n    \"$8iZd#MOrdQUk7eJ_0Se%+SVe[4<se;&-Pfi`dof6'15g]B,5gEekPgDS`.h.'HMhqHcih0,F2_)%E'Mq3O'M34O'MfTFF1PwewW/I&(M4Y0(Ml^9(M%gB(MHkK(MC:A.g4hS(MZw^(M\"\n    \"(#_(Mw(h(Mb,q(MM:o:lppGGC1voE@=QS-QR_tQW(Y4+#806kXQMK/#h&^w0c1xE@Ii6%#oSu92D1=6#>Ja9#*3YEnYhN&#+6YEnbSHk=wf%:)uGdw'h#N-Z4U.F.7mw^foZ4F%t/6(#\"\n    \"J%0:#DA1R<eD1R<w5L_&YKU7#3;T-Qc.i$#Kh?0#tPJ=#YXK:#bMC_&3kN1#px53#CmL7#oOs9)D<t1#lQ?;#]IX9#Y449#ch':#nrC_&G[Lk+N4k)#)ZW<#RFP.#vHcgL0&,1#sRR(#\"\n    \"`2G&#Kc8-#phJfLfHC51@/cY#,@[Y#D1`Y#qV_@-X3kn/.>_Y#<e[Y#GM#<-C<D].Bo_Y#SLE/124[Y#DmbY#VI`Y#MTi].%YZY#h3S>-02RA-oFuG-8JwA-GPZL-C86L-Mn,D-,R[I-\"\n    \"b)=45CHbY##3^Y#Y']Y#Qc_Y#e?]Y#mU`Y#rqEn/))ZY#i=`Y#V]Me.4?^Y#iYlS.*q]Y#s8x#/h%`Y#Nfm-$g0aY#?MZY#3Nei.>IaY##bDE-wYlS.$4]Y#U9Bc./NYY#D`CH-#DsM-\"\n    \"El6a.mV_Y#FeF?-v+f'0BsYY#M=aY#n%kB-;[Lh.]d^Y#*'KV-J4S>-U)Xj.3$cY#a:7I-jk*J-vVjY.jUaY#x>EY.ufZY#vp-A-n:7I-KbDE-uW_@-NgG<-PgG<-g4S>-8rdT-/.OJ-\"\n    \"ODsM-/)LS->&kB-6Mdl.]@]Y#/spk.IY[Y#_ufN-;FtJ-wXkV.:%bY#t4S>-4X_@-d+Yg.Tf[Y#&HuG-x*MP-)Mx>-`6T;-dUi].5L^Y#/(-p/nBYY#m>`Y#4%Us.DoaY#g[k-$.&_Y#\"\n    \"IsZY#66ZY#coCt//p`Y#EX^Y#X&,s/.d`Y#W1bY#e96L-_Y?T-C/s:1hK_Y#NNZY#rW_Y#b3RA->Z`=-a5?l.'obY#C<Z91o=bY#xUbY#31cY#;%jE-TaCH-(RZL-[4_W.p)[Y#TmM:1\"\n    \"<5]Y#Mf]Y#@7YY#NU]F-HvfN-N2QD-<sdT-C:6L->LwA--)l?-_Vi].Zs[Y#MxgK-@fQX.VJbY#tlw:07&#v#[0wu#TLm-$.w&v#b:$v#oR$v#uawu#gM9g-9WuH?x'ZYY-l68%Y86Q#\"\n    \"Af2;]r9T1ph6=W$G(w2$)rus-[B1,M7C>,Mp`7K%d5%V6rd=R*m=pO(FaKZ-<IXD#`xeH#'K%L$[8+)6[k$##$&###pnuM9qV<>,83LG)^b?X-0k'u$ZVd8/7%x[-;@u)4u]DD3@#QA#\"\n    \"C@<Bu]?-H+1q/%u[xS,2@TD%O]QWH*=E9o/akX?.;IPAuN'^:/*CH$$t,Ov0+THV%u9=h>A@h(#)+ei05nOJ(j7(s-q>>x6Lf^I**YN]'JM>c4kiE.3.G^l8`tL5DX8i*%48v*?EGiE3\"\n    \"U(cS7J?.'5:libV9&>h)lY67CMwCT/*KwVu$O0O0@ZZG32J:;$7/=GMX0:e$UNc##D####,03/MuwSfLxBS#.u1h8.<2`^#J:8Y.pV*i(T=)?#h-[guT#9iu&](?#A]wG;[Dm]uB*07Q\"\n    \"K(]qFV=fV$H[`V$#kUK#$8^fLmw@8%P92^uJ98=/+@u2OHI.o`5BOojOps+/SxefLqJd5L/AP##x.ju5oZ%##gen8%>I.[#J><j1Axms.@`4I)kHL,3S('a#C*9Z-uiWI)0U%],@J))3\"\n    \"'b*G4&,]]4mm9h$lUFb3cAwW%:gJ/L]/sbrMqV,FH%o*F4rnjuqWL/)X.YF'B%Is$sc*o7CP75bVt%#.I9g[#j-bx-KDc;b@>]BA8Dw;8'Q]^$OE9E-iaE^,'ktK26_ln0d8eV.AvH-)\"\n    \"e2q^#WBBU%Rp14')Co5XCMUr.1$8E+Bv)(T<Q@gt^?X8A0O@_8q3n0#Qb.Rj@Nwx+Io9s-(a2@$/lfe%f,m]#YiVD3?DXI)tSGMTMhrUQ.w8C6qFf473G(].3B$VL'36rmE.Jt(VSBT.\"\n    \"d_R`8nUvN:AW9W7nDY$k8l[=YQlRfLX6D/%4&q:#V7ggLw9MhLkIi8.APRZ$Kk(9/,dt1)`k.T%6D9C4/_XX$/%uN+eMRG#u:be)Jq5S7v@te)e_?oRm.T(shuJ2)5E,=5%V^C+wmx1'\"\n    \"j$M@,k>,0'jZ,N'',JMB,>js%_J=G0#fJP:Q7Fn-)bb_J1o`i0-c:?#Yx_V$Q8QZ$wN8@TQ'L>GZ:j7@M6o7@K&.F#o`6K#'fBK-X6_s2d-3205oHgufv^FicGb4d_M@OXa0)6XKEK3L\"\n    \"Xr@/LUi8>,5Wx88?fp58wiVD3n>j.3Th+/(*O13()MQ##Kw.uY8OPh1ZFs3Ma/9U;uTAO(Yn#ruU$GV#J,H:Upp9YSE?66LEDI=TZn#xMYoECl.1NP&#&5>#0JE/LQiou,<@,87'n>PA\"\n    \"hDQiKRrd+V(4)##cT^:/x)Qv$lf/+*s<RF4`pFn/:=]:/:5Rv$t*e6%W(/;2;`l<2XX'*5/xs.LSbuN+aU;p.hH@E+p^2I-#kJe$%N-@'RE%Z$[6H]u`$G(/o`Z3L)>j$bew,?8`p&<A\"\n    \"51rd-]qsD&`$O]#E]J]u%o^>$@+K`t/uB#$EFG]u8neF@):lbMF;#gLvp&-#T3n0#ZdtVfP:?>#F^'X-A*(0Eo:eP0Qo^h3MefL;*x>GM3.dW-Wm.6+G##Yu#OL@-#M,W-39Y%'-&e%'\"\n    \"?7P&#6Bc0.m7'58:.Y&#u?r?^sQ.29$8kM(pt//-VH[lF3$mx43j@+0hrVB#vO:&O'o&/L;x+Auf=[l+-gWB0x>nA#mqF8Mx.#Gi)J+Au/uB#$8K;L-r,[&#KQ9dON3bn<cBhQ034br/\"\n    \"l(0'5_FgfLuhO48U:[l+BR[p0[;rm&O),##7XEt$=bx5#J?>H2F(@8%&Y@C#i_Z=7No^I*7nJ,2Wt+N'GM1eN47DcNF<w%,(o'B#`//;MJ)Nfq57x:.3.v(EL.o&,pRpq#3xR/ME$.ip\"\n    \"cS'sQF7$##lnr?#&r&t%NEE/2XB+a4?c=?/^0Xp%QbUXM$?YCjwpRX:CNNjL<b7:.rH75/1uO]unpchLY.s%,R=q9VEC@3`Rqrr$V%-tLPNV'#i,>>#(_Aj0H=^v-Ut;8.X5Gd3vf%&4\"\n    \"Z;5-35NCD3/k5/(L?f;->1/O*g0(,)1[94'eRJ$l-MrC&k`lW-i*&XJ>([xk`N^$9J=RYG';ds--j>R:)#.xgnv?D*WKMwgd]tfMc<w[-St:AuB5,O-2G4.Zs@<U-:aZf%P5YY#NV%JL\"\n    \"/GY##,)r%483LG)OoX;-O,.&4,9+G4m#:u$Nghc)4N1)3SbOU%5xkj1EHuD#d08@#qbLs-oUFb3Rv:u$li%pu$,IouH%IpVj8,+-4pbQB(^%r`8)Y4=*'=n'L'aX0+3oILQlVnLuq&/L\"\n    \"ImB-34A-#,eP658?_5k0wj'j:_IVqL>wV+4&;L';W87n0ieYeu,0TEuq;BO;7nSe$q3n0#L#^q'Vjqt%.lYg)jAqB#BQ'T.Rq@.*AVT<M>KpHRTcQqO]*Jq.YwaaawDBI$tGjdZ67=NN\"\n    \"WS;[G'rYW-042X:eJ3cM)1#,MoAKYGvU5W-u:at(4[QZt.7$Z$k:xjk*U#H2Z:;8%<p&##J.rv-0S<+3a;Fc1@4n8%%MbI)]::8.X.a$'+`kGM2[AC#(O]s$ax;9//W8f3&,]]4RWgf1\"\n    \"Ac``3%&AA4on.u-*dfiLx=>c4sJ))3pM.)*02'J3?MDn<-Vi3=4AWt(:]QA#=*W>h'Q>q#:';K_ai_2:7Mh=Q3'NBOF2n3'451f'15Wf2H<qj'7Ho^/4wR0:l@mj^[m5R&-PGo/>d8B+\"\n    \":+Q3'<>A^PTa5n&$<.=1Ee(hL3Z7)*>pRg1]<GLkdo/#,_2F@?#Rnp.>FmO*_>>(,`1cB(cUNQ&8$73'UO9:@f+mb+wZLHM+[Uk1qx.n&C1I#QP;q=1Q2vP3@S6=1GpY]#>Yqr$NV%JL\"\n    \"Ren'&s3DP85Z&##$Tp<-HHHQ'cO&2)%M4I)A/v[-@CI>#d4NT/V7@W$(_Aj0j*am8s,#H3=6F2MVE8x,8&B.*EdCO'^e$IM4,u4S-3@2Li/?k'mtf&$ISW1BrsG=%Ol+J&YmTr(2'-?8\"\n    \",K+<A#CNj2YF:q'0;PS7D8uN9$f8h($6CT9G%@6S'lTu,$94c;+>8L(bf4_H91*p%EbP`/9GKxIR]%/_bdKaX+IBu.`HJfLQbQuu)]qr$#E>##WYCu7:6^;.5QaU-kP4o$EX<?#(*^s$\"\n    \"Af)T/ZU)Q/Je75/sc@A4I/w&Q-^xi)k&PA#$(DE+MV9>#8Ht7/hbAa#,DS47H'K2't0pEu?[G3'tvNZ#u+<Q-M=g*)h_=h(cblY#:'wiL[,b3L8$EE+`GK;$TC9qu,OPm:7fCZ#*?&i%\"\n    \"$RRg:RbMZ#&EkUeo_[h(OZ7X^<LD?@Rkrr$(6L)0aKb&#C9OA#FpbW'&-2K(=5MB#57qHM;`pZ-hHx6,Q>$Et'@l(5LEF$0%IFL#[/;Zu[$^iB841'5T=OGMok@ath@oY-lq;[0`b9au\"\n    \"+#W?#v$G+)24br/k@c=#,Um$$NV%JLYr@/LW+5;-ir<Q1BSuD%<XijVtf-/(+gnP'SgOA#4W-/(n5pV.lZEU.vr./LC,^Q(7aL&l<N<T'jjX-RFinWtDw'Y#e$SYG:4)kuD+eEfU%]H#\"\n    \"+7=*$3hNW8.``pLA%$uu#*Vw0Q<2^#YE([-<vnd4QI$##K@Q##x_BP8Vtj+4+9ki0SBo8%WM[)*s<RF4'^9Z-5JYjLI/:Z-BEEw$ZcCv-pk4D#B*Gb%[Cr?#wib/2+LTfLa0`F*dw6p.\"\n    \"^j:4'U#J@#ZTcn&8tR[#1@Go7WjLG)1(P]u1/2i1W^(4'T=6F+G*ET.d^=oL;w(hL([2xLLw(hL,&V]=et2?#R'0#,vsv8'UODZuY`C0(`eJP:DP,##,obxusjZN:ZVjG)s`24'oG?5.\"\n    \",NrgL:'(1p=)ofLvprr$VpK<hZ(V$#0>N)#B>oW&-]#<-%w+1'c]<+3b]J,3W?T:%tc(T/cu+G4)?c-;cvPg)77t[$4Ca8.OQZd33POg1%@$EtQ>l(5P.AZNh'XfNU.5'5d/fw,U<1C4\"\n    \">ii&-q]hB#e;,A#e`CB#x,N=M5;nx-a8?/;XlRfNTQD15'TXB,3[,.)+4850&CfU+3-g[u&7dp0m,T%#xD-(#lmMbNnJXD#fkIp.YND.3TE)617etD#JXL58>Da@$NgZ@bPR2ZuXvET%\"\n    \"pRJO'1TChLTRjJ8h+*vQ=hf4(t.)w&NVS.&(9s5(VualAdDDO',3X[#ajF@&(OWa5aKx(9vjF$.BSUv-?D,c4No^I*4qNM-%p)..E:2mL>-PS7LMtjYCU3[ullgw1O0GO'&2487JY?%b\"\n    \"tv]hTF?6##9Wox$(2###SKb&#t73j1p*mV-<=@8%L)?s.GVLW-@N?EP*7P.)=8PY#eAY>#]`,5hBk%?5ltKH#ApA?/(]'O+[fUN&arbS7liwMp,rf&$xWY.q@$'m&23BkuRY29/`Uo47\"\n    \"NR7*+)hA@uHM-?.a?W$#[`)0;7tVw$ax;9/*-+c426.)*L0-i1;d0Au4Jr0(?ptY-RHfS8iew_#$ltZu^rq,)E'J'/Zq%[u>sAjrNFhl8dv]G34Q*?5[q'E#G.,Q'Y&l]#KG>c47f7%-\"\n    \"Jn@8%b`vIO_/E.3se>']m4Z##M]Oo79+`w,U5g`:L.m<IXhn/($&M(&CrXeu9=)bYH:%N#A(1L,#cQ##M1r7/q.6DO46(5%/KB?&lr:c%](?eQ4A-#,$%(#,Aq+VC;-8L([.Od2x@PS.\"\n    \"kN%##AFDZ#5D-W./(]$7MFw[-9grk'$B,IZe3YD#2G&NiXhZLMrAo8%(H5T.t=r$#7dRh%BmuX$KOj`ub>(6RTcZULbR39/oBfU+-p9x9SP>bnQ5&X%pbO-)x3=(MvNK@N8$EG'i_7MT\"\n    \"v+qM#ReBtLg@RxktpqbrUv?rC*+8C8i&X1)e61nLx-$O*%@h-Mn?DX-xv@=(^()?#U9]nLYV07/qx8;-1FhX)4EQiKjh6_Q%Y'lUjVWn'S8dk2HluwPc13C=7SnW&F,B.*Nd`[%CthT7\"\n    \"5%S)&>Xd--5.hk+6T9@Mhk^gL<ifbMD:#gL=4fK>*mkA#/IZD-(76<-R2o'O4N:`3Tch@-q>)&.2V>F>Dv0^#,h]c2-JE/LIPou,ESXV-*/rv-Ox/bGmrfF4t<7f3a49>,mLREn7F7##\"\n    \"(J'0$.dYD%s`cA#H(:J#Vp.'5Qi;=EedBeu@i@+0i%s^#/c5fa9RlYu#)G75ng<7%?bG/LlGQ]483LG)4DvT%.W8f3QmuX$8'E<%GO=j1ld(^>mUBN(QV>c4vb6&/a^D.3C-Gb%3jES7\"\n    \":vvddaIf2;ICg`auL(eTq]3gOs5aIq/Hp7/)nIro,?)bK1(;oKPX`B+Aiu.:a9c3'Z$]<$e*V-4-e3Juk:AP'$rU41Tf@E+ClkG*V[=g5%1)e3K.KfLevhP/Yg8e$D>#+#%m^m'W::8.\"\n    \"T#qG;U%hC,.e_F*O29f3nu_>$nH%x,A]DD3n=m;-aI00/TKc8/WlgWh/>.Q/OpjM)*j^I?M^Zd2GhAp8sxbFiV+cFiWJ,$.0*9l+Y/]7*_2//N:lmC#0Kw'l2I[OX^o#a=$'8h(0GXS7\"\n    \"S-Q@-h'VQAwu)s$V$p[t0L#w&HsAL,2Q^[M-#qh=[hcPXLLsqe:erou:w,L/JP:;$D0LhL%xiI.9uYV-?/.T%E8mA#OZ>x#;&X1)%lp[tNgAE+#I[c;?u@?$E8oU+Uq[c;YUI2LNRt9)\"\n    \"B.KfLKL6##G^^>$>D9C-VHH@.Dnn8%$0$N0r[5l1q:gF44+]UR32t.L-gnj'HZFu-9Ht-$AfSl')PncIQDMnSB;@p.0%hf)2>tm1>iu8..P0^+YhG'#'&>uuii8e$Brpk.D1g*#E)V,.\"\n    \"kqt(Nb$,G4#g``3I^4L#TkEl+['UfLWvNl(+IHh,GkRP/(krj%N);cY93p^+hJBM)_[Lo:he<9/96&$PLAJ.h(?p7/x2Q;%&W/NO&hRj1P]$1,^VW^$m'p_u*2r:6:>6S/DijB4Yg^R4\"\n    \"5TTR/NuAv5bXZ_uD*o3+=?c=$h[uC+;;%@#mia9@<S@['W/=jLnYa,#R8+k%(@(,)bOPV-rZ*20,gYc2>.ku5Vj[i9oZ%##4*x9.GIgZ-t&#A#VRG)409tM(=n1eM5=`9.:#G:.DosY-\"\n    \";p,g)w_B#$1lH)4g)C<.msXq.0`qG3u3V'8#^i.LOc%/Lxh1p.OSLnu8_C(&L)G>#&A(v#L>)0u$oK^#%_%L#1]Nh##]txun-Lk+F)wIL<WK40(ME/LN6ZS7F2KX:E_G]uY^;^#1ILC&\"\n    \"DKX$0siIfL)oEB-9I,hLrnS+M:.,GMhY5<-vOlo.1&>uu&[Gq;NIvu#5FNP&EQ(,)U]W]+fh18.vsai00);D3Zt$##Pg;hLfn/,MgxD'N/:#gL@^g8SMvL<L,XK<Lo@pV-0[7nj$]'^#\"\n    \"(Y+Au#MbA#35sBSZPD`&wIuMt(aa@t%j&]teP,/$[FUDNKCZY##:HsRD8I/LO3cA,kv530Eu$s$;)MB#j8%TCl-vG*Q4@`ap$v3;-GD&/='dd3[jq@4Te`h3%xP4L<AJ//'Xq0,9FQo7\"\n    \";EMc)<*;SeTD%D#$m%.4Or<V/wPR&#6`xb-2WJRE0^c6FQKv9MA5MB#FI@1M&/$H3<4MtMJ*dTM7dOj1>+Y0/@_N2L&9*=VURA$^WveiLjubC.KJ&*43K*$$C;.JLD7$_]pTr.CB,'##\"\n    \"BC)?#w#9Z-d.<9/QM>c4JiZx6FHuD#&]bA#X81O+nT^:%5IL,3b2x;%.0ihLq%>c4B#4-*i`U_&h%AA457n2&5$0fNQ.h'%sqA[u.b#&8c5m'Qt&:u$.`1?#LQ0u$rHjv#I88#,j.e?$\"\n    \"3u_;$8K$.22iLZ#O^9u$]PI-)Fp+',YK&[##ZT1*'QTm94e8n+[Yaa*W0gN,9%//1NB+at/NcN'VvD'+rfGb%f(YwLDd%FQ80MC$oj(*uGfGMEJ'`A$-sJ^+d[c_+:tQ@/i/CQ&5YR&G\"\n    \",,N[$s@kA+?Y%9.cIGC+(QKZ-%R]@#PW]#GXpYDIMP>_+P9cx#GnOm's7Ll%7#vtN_b$##$&>uupaUV$kxw%#n#]I*j1)W-I)>CdGuX58n_*c4ss*#PB5vS/B1$(+hbd.:h)m/2UC/i)\"\n    \"t2P'&0pBDt-T.8'J$_xXuB?/MbKFp%3e;s%'?BW-C+^&Z_?<$#t7E)#_>QJ(C`:5/wAOZ6>Ho(<2E(a4dPA3%qQ)gLJLpk$6M6W-dka<Uq]B.*(>3/LwnL5/x5]CuwKP6<[W^/)58WKj\"\n    \"R@)J'7Co[7&P8GVaMMoSL>&K<A0>>#^&O05oR0cM/gKW7MBL-)w1>X(o_`?#1%bf#wWcr/PYDW-VJ6>#B6>##UjxE%T6###K?O&#L####0k'u$K.oC#UW$Y86IXD#N+^v>%8-4(^?>WY\"\n    \"ia*2$F<oDS7iP9Mih2]3(Q?`#&&m6)iKk*?jvK#$SE?9/]?UJ:PU%cME.gfL`60r2lEXeNVielAW053`5(u48E&s<%sg%##pv@.*;_#;/U-7@$L0CD3$M'+*l&PA#.QBI$ubXI)12d8/\"\n    \"t6]8%uV))3%I7f3Iaus.T]WI)8'J.*,+P,M;].-%$t.JhMn:T5[5[+uIaM78depp&U?C1Ls+Em-DZ&[>wf[-)o)v>#CU1N;8NP?$rO#V%SewW$_q.YuR&a-,)'*($JnLun86q#$Gj<pu\"\n    \"f,p=uBQ`@%sjJR/YYbe#btcYu*urLThx*r53Sl?,g,>=$Wd1O'9v]&,74[s$Q^u/(7>&Z#dFB?+t>hq%oC&t%`d>N'jF#$$NV%JL4*GD3d<ai0/H&##]fZ@-iKlj1tCn;%lmkK)KI)v#\"\n    \"2r-x6NLXR->ePhL:x@d)XMYx6%(-?$PLd4(%/u/2]m-H3&Qmp/n`WI)Yf=Z,#Jp;-%DVo%cmri0)/ESIDkF<8OHMP:C;P>#I;lT80]eN3#dJA8YN4?#mk*j';u9Q&ET-)*Yp?l1ml]MB\"\n    \"NfER*akojMUbP]-nwQ,4GYm^HI/r81j#?eumqbA#SC-61@h+=$lC6w3J=Vw@sj-B+rK?V9FJ05'oX.c+(q:'ud1-a*,K#s.aI4+3-hQ*1FXRW$(-Mc#6%:]5u8Yh3dOFA-f&[.S(2u<9\"\n    \"[e@%#$&>uuW^UV$2'*)#GdF0lJP,G4EF(*4][_a4SwC.3nelv$@=@8%YuOv$)+%Q/q%^F*X;Qv$axWvG?;Rv$K`Ud.sJ$5J95$Y6dORX-eYQM27OYY$Y+))/FhNp%v=@W([PDO'4'D$Y\"\n    \"jgoj014>/,3Q/4_v<^P/LZ;?%g/cP&xvpQ&?VXe#?LEp%3wP:&Dm$.2v[VTRaprx%<Oor'+aq11tbe[#75YY#KwnPK`l]E[95n1K%ro,3x=g;0h=U%6KCdERh%AA4YTrq3gDQJ(/fWF3\"\n    \"FjE.3kHL,3d$?87,CIQ/jpB:%()MT/((;j1AfsF0X@[s$v4Xe)^=O,krT^C-*69[3UekD#&_*G4RI^V6n1Bf3Jj:9/:tm;%IkY*73*wlf>F>OKLSl-$uI&d<iXoT%)@XW4)jpW['5dc.\"\n    \"nq5Z,YT'U%jwE=$o#FB,msG/(CbJm&]Nb]#n=8.<QiC;$`-jm/MvMv#vjkUm?KkY3R@tiEU4v>#7OjP&ig3T):0jD+VKJ'/'B<iLq77?$g9ST%&BC;$Gei;$+Y_V$=SG>#7^nF,a0L'>\"\n    \"lc`E#9cuY#-c_;$^GbGuNX1_Fx5vk0tVQN'I<UG)sjxo%1J8P'_d:SC>g/bHtQD%,`Psa*sgQ8DR<8@#Ll2b$WPY##`iw1Bd:(##puN$%0#fD*xUcT'+`NT/`]d8/X@[s$7q%M)v0Tp9\"\n    \"Jn9a#6xH1M0[tD#F7YB4w+m]#lsB:%$3Tv-hHeF4Nr0+*t@SfL7-]P/H=[x6TOr_,SA@d)('[d3J[Bx7FBLQ91N/##j_3r7n.CR'+GxV6'T%iEXMG>#jl]&?v)Yp%-Ml>#.ih;$9-8Kr\"\n    \"*:?a$4T%p&0q-B$FxkS7ZAI3'7,^xt:'>j'JtM=->KB40ssOY$.SC;$Mi<aGFSRU99+;Z#**B&=_p/c4lcKw78F1H24heVNL_x>,p,m6:gQCm&xl69IejNi(I5':vZ_b%$3g5x#mQng)\"\n    \"6gC^#68hV.X9&u-xds`<DsO&#BB@s6%;-5/'Y'O+:j_u$$ct]u5ij_t)uY<-%Ag;-7q.>-%%Z<-5u]GMbvX?-$Ag;-)h(1&Rl*F&4Ml%uQ@G#$<sHw^/:$Z$FT2Au,u'^##R6NaxTDq7\"\n    \"NX_,F:WAE+[5JgLp@.14>4U/VZHvxPQYqt%7WO^Oe'021BhJ]=h%Ga?ZSSEA6,'#(X<<nANKPd3sJ))3xFvxP)3f6/Da14'GtMnS%@,gL7ifbMWFuS7tw^[On98Y-G)G(/fFl%l*anA#\"\n    \"UGZW-]L=r)F6jI-9%.Q4JPUV$n's<-''UW$df)T/al+c4$F3u7kE4E,Kbb9)F(vYum*;?#h^Y3'xuZw';b)9']6=t$%@P`t&o^>$OW@`&JwU#$Rp.F.wHB&,3HK/)nh%xplVs&#Eu$s$\"\n    \"%0p8.SA@r%l.&@Qak%6M<*=CMTh>;-G`74'-ZA^#(2a'8kh%[#[ULhLU*x4&LJlq7#5cA#ZaKm/B3=&#IA3I)SLXR-J*eZ<1jwA,3Y5lLTE2-*_.=6'[0sZuZ7IJu.+wOY*;HLItAGv(\"\n    \")LjQ//f)%bwvU,);9jUN/uxIIpDY;)u87[BQLH##UjxE%)8[0#8xL$#p8q'#=''u$+dfF43c?X-$X>r%melK&fX^8/KJv1'LQ#]#%2k3GSk4#G5GSS7s<YY#5d1bnnL>6sT42sDu/h>$\"\n    \"YD-t.QLUnu(VR[0&>K/)+34C/-PofLD<K`tcu%?AWNt$Mx-,GM@=?Z$*fF.#=F.%#bWt&#M3>V/2T/i)HrUv-F^?d))2pb4YIYjLeC0@#H`G>#KjE.3Z_[@#1N.Q@2eV5*k+)ul=^hA4\"\n    \"+;wA4-l2%bt_NPoN%g1BYb]+42bMjLXF8:La,3.M58+**ZX9H3JP`,u2U`k#Z-qDX;BgF/['9'#CS)42S_d##(FWJ'+2ur-BL75/W76;-H>TjaHfu4S=1#?(NVPp'-^pA#O%8P#+U<BI\"\n    \"s;f%F--=r->#M#$][9:h$#bIh<F;x$S6[0#=@%%#&-]t-a@:[,c@J,PXX?##-^7,RjSeDAZ+8pAtAm][=m)Jq^^'=-D,]n$$eL7#f2h'#*lwU/Lp:9/^RIw#YiWI)rNTu.u&Vg%mD,c4\"\n    \"/TYx6.e_F*r(K+*:OI@#$N6;%T6]8%tsFA#8,97;NH`IhNUcIhEZHc?>tq)3Y@h#,cg#)%pq.b.<T,[-<Zi0(ik8m0I?d)4DttAhX&X$3k=h'&40n0ANg4^,4ipRWIg#?[WFc`sY1vr$\"\n    \"kP2>5Tjw.:fujo7t%:'#Wu$s$/&3,)/he58BHMH*vu.l'iFVdE=vj5A*EY=7tf>x#`1tM(d/Z]4V)ZA#tYUSIZf'#BV(kM(KB*=-::m/=WF1%bfS'JI1IvG4DU/m&659F*9NYI8%?&'$\"\n    \"ctr#&PQopAM4X1Bd#mS@gV@l@DsLoS#W_pL%DVrAat6x9'df>a5_r;IR+m/(t''_-aus^.Ao*?8wwn?9(IUoe.ZQ+M]J0#,R(dV@(xs^-K4n0#tlIfL(IK/LSIDM0'0&##&61X-VT+a?\"\n    \"uc2X%@8;c435-J*SC%s$ax;9/Oqs>-Yo&+*>H,h1jE7f3OPWD#OJ,G4x2shLg-B/LaoJ'#^U>C+d?#t$U4*l%JC;D+I;j3p%`T_+Y23KVvK<DIsT#V%K?96&k_[<.HKR#6woL@^ciB6'\"\n    \"^BA@#1QC8.9sl*n/J#_+icq>$o>w/1$g53']*bp%+?$JLwj4O0E;]huMjiZ#siK/DrkZi2&n&f=104-*$8GX$PEo>-WVuO/(8[0#'*2BQ=,f3%$EQu0M,]n$eKX,*4]f^$pabW-rbkwp\"\n    \"b^+9.C=7s$uCJ-2FORs$D:uhg?vT[uj5ZCF&l'B#6EmtL*YEl*Em#]b^TxW-;*A#e`d9M'$<'w#.i)'MD$p@#S_$x-bD.+MR7emLxZ?>##&5>#0GY##L'B['7x4gLQROZ64f*F3QDr$'\"\n    \"GL75/u3YD#)fXI)2E&C%UEW@,b<h;.8Y$Kbg8(u$$8O,3Jva.3BPc##I'1,)RosILiW0KM0uU5/8q[gu,s?1McWA@#;IcA#SE2C&VrHh,;LQh,I8YY#e'K&YiG#@Pj=.B2Q^UV$r(+&#\"\n    \"q2f.*dZ'u$[>sS/Y13K:HUMh)O-l%$><)D+x$1v%M,=#&l=RW$%<TB+/FXo&^%#/&J*#K+9aCY$gi/9/KM5Z&1s`a-b91_A^`S`A)v5UMdHhx$t>3/Hx*3A)h'2H-N<DtLClTB+oBdkO\"\n    \"(G+gL%E7uQ;_+c4I11Z$6T6p--:S'J[[H9i#'CY$'K-&NN&Xb3SL;CArJ[j0u_/e$hg1$#3%%s$oUFb326.)*J&jKtM]'Z-1$JI*MNVu,d)CY$ub;4'HFpV._Ci8.Tx^##%9Gm8&B$Z$\"\n    \"]xrN0jH@E+cpo7/=l]fLrRaIL8F6Z$K5@kr7WAE+NUj9DF&###_RWYC`_Y:2e?8.6:2h&6?2kbNgx3+N[ZlGMH^o8%B:)D+]r]i%0IwM0,aMu5^-+T%9G(-MngcgLi#CQ&4cX.M>%Xb3\"\n    \"L,5R*o.>J&4sDE-Db+w$RJQtC+27>>iwwT(88lSRn:JW$*VQW-GA3BKJeWDXp?0B-Kw0AX9)Uw0FKN+N)?-##$g=3))xL.QVKovOQvksP*<6E2wfo=#57@W$4f1$#Q$(,)2h+T.:2Cv-\"\n    \"3Oo'&q93Q'<2_pB5f+o7ke]Yc2xms-P&9kLJ9MhL7#*D+HXHE+$GX?gvdSe$=).K1(QnW$tH.%#Dg6)*.Trj;)j@c=44dK)bk]Lp_%+.)&:x#/b=+.)A3Ob%^ZB=$6T)Wu%OPdMR-;.M\"\n    \"D]xIFO%lA#1w5D-u=RA--LNNMdYE^-Hdv?B3;4^#L.PG-gX`=-f63O9xJr>Rxxc&#S,>>#+87<.8KJMFqL]L(1fqc$atuM(4(XD#'K+P(K?(P:pfd?$$8,xu9dV1L6$E3t1<,A#01:B#\"\n    \"e`CB#8qdQ'_C;mLcb=<%[9mA#52^S'_Bmp0EAtFNb/@fQGjJ+MJ[AE+dZYSMh+x>Q=Z*b&RAR]4ggSd3lZ*G4ZoCp.H7Gm'*8_e$xiWI)$PkGMA:XF3WcJD*JP1?%?=F9)`g0.)q@2D+\"\n    \"?DiD+]^AWQ/.p+MO+%X-7H:w1bamA#gfRc**P18.Ogi8/&^aHZ*wR3X4]SfLt84D#i+P3``6j;$-*Zb3+>:el+Jv;@^tq(E*lVI.S*<$upBD$$#iXt?]eU(E(:Bg/)iXi(4`/.)7N%j:\"\n    \"X7G#$3:sp.NuJ*#x/2vBgs6l1qCn;%ZC(LPGP,G4_R(f)R35N'hl<M%>;gF4l<sS.wHH#$b;eT%^IfLXS9Qw''IXm&=S2]-J3(1;$<6jDhRub'L8c>-cp<)+FWKr`v1)`IXvB^#iH3Q=\"\n    \"2di0C<fqg*b4[8/N1=YHU28h(>=LX69>ne2ixi`PFK%M&>t]f1dv`wg$0+dM/,x9.i`5<-f1'bDd(u&#a3xp(8wip$3*(6M>#TfLK/1S-A5Vh.;#S[#R>ojLdR@%bw>g*%>qVYP:U:C&\"\n    \"DN/G[b_IT.]a.-#qc)t%FkRP/w;_p.ms#E3UqjT`%BqB#wch[G#:Ev6x)8F.#<7x0vsU;.,7]s-x@7fN5;ClLJEWVZLZ29/m3hfVPeV1Lr'onV`?4R/-ODE+f$H&W6[*gVG@';MhRv<-\"\n    \"::/Z$u(F7<Is/kL2rE/NfUI`E_3d<.8rju5+i?8%UXHhMPKZd3T+0?H/b<#-9xVp.axJ+*$R+OW<xA$R00e&OTE#W-JC5F%@xsx'(sieY*R5Vde^5%94%W-cYnK;FTH;s%mYYW-iM'h3\"\n    \"a'tj*:am7@'-'[u5mRhCc8N;RjDKe$9pv6J?n6^#$l?x-7a/KMXBi-M45RA-T3@i6]Zu##WEX&#*lwU/J^D.3jPl>#G.,Q'M0/%#=oAD7ivrKC<VIg:H,wFuvsOnF(#V+ueSw^N@G<7R\"\n    \";ME&f#8wUdNNnJJ4GH>,%.C>,nG>qVfK*X?@K]]`[LB&RXk[O#'t6ouuo#BJh;OA#Twm.MJ$<>0XZ,A49,P,;'V`$'+h'u$)T.)*M7%s$;)MB#_rHs-*dfiLwW*?#<muX$Wj8CuZ^(9/\"\n    \"Dpn)4G^>rHP3R]O%&^:/ev(^uK3)u3h_K<L(cZCj$H-K;n))&PI6`^#Dp[j:V@-I-8Q^lF&'Gp.X7Yd3J3D]f1%vW-oJ(o(l-f`a8C%^/4AYjL)Pro.,n<u7[@J`aUIJwK1ZJ+4QjX(/\"\n    \"tm7lL]cds.u,JB.u6r-4EooA#w6lsL>N>rHbU$A/p=tX$]-wiL1-@_;'V[gs'gI(>M12H*VP[)*Hee)4WAYCj?2pHdlDN^#?n+G4-YOs.+NfmOw<$T/uFPS.$&>uuE9lc-)]]E%iFB@%\"\n    \"FZobZ`6_S-je48M6_-lL,/39/S^J+4Ia/KMGS75/._#V/ViI`ak$[@HQ<nxO._g:/cmu]uJ3)u3C49Cu)O4Z-695eHl@r2LE`d`aiOv?eH,+P(&b+X$xIkI);'r-MOaR_#f2i^oVCgG3\"\n    \"%X)@[Tjt]u;C]:/F^BBTXTi>.MvUk'R3Tm&?`I34s'o7l=E^[#JN$q3;)RW%0<,A#/@PD4I2?[CsQj8.acRL(p(n;%Zm21d?R#N#;DOjLIslP&6hx+2kYqG*^Ro*&7n@TKb5QJ(9VW/2\"\n    \">c(e$_k4D#9Y7c?F>a+rrx6NQ7PqFEa=3?Q?0DB+e^_D*8TV>QfkR_&[1D?#:$_8/%]v7/[6vIMw*Cg%1dRt1NGf*7`%<U2C4XrL7jXkL+,V]0%)###Gesrmv(/GMZXXF.?=)?#<'7^#\"\n    \"wjECS>-YS7dC5^#D.PH81XX&#aq`PaH/->>.*pAZBR+W%8Jf&4<muX$Xd;^uO2Oda8.c1B93dr/U:w$'hUj'0hu;;Rs4h-N3)^fL5&0/LSi:j=0?m`-3'On<dQR$9x0m-?(Y;[0OQf9v\"\n    \"Kj@h$.eZ(#C9OA#B.i?#IPJOX0Yd5/ZI:E4bQgf1Mnpr6tTq`NkL3E4pM.)*:..W$0=3D+i*]q1DYgh3#1.bu2bJqLI%Si1fV(C&:ClA#B$AY-$UUO+=N]X#3ML@-%GLP1i%Sv3FLpC#\"\n    \"%.I`+bCh--V[QTN<ZCD351P]u^#s=-VH'D&n8W]+#<WNt&?2g(sI9jKvqQ$$cX<9/#3m;%G&u-;N+_^#LVVO#fZHb,]Dx4]fFYF''?0I$$_uf(x[ZajVmLK(c(5b'aTbKNW,%.qmwEI)\"\n    \"fekH)JJOe#U`3T%;ou>u4%Dk'OFc>$&u9'#o.tS7>6cf(TE6Q9YFBN(j$0N0OU<9/-d%H)jb$lL^Es?#NMhP<k1FZ%jOj20lEZd33Y7%-8]Le$,7cI)JnK,31A)ku:Y6caE2w=5UoPl0\"\n    \"i0Y`#2E#n0PDN+0JxIO'5H?at8/:P:T[03_:f^'AxgM<LX$p'&sP+b'd/@Se4N<`+H>-nVXTF+5=`E#-el5`-<Uw8Bw=EO'/19h(2&Wq;>+cnL_Ns$#R3n0#VfUV$dM7%#-5p,MbGAs$\"\n    \"YiWI)+2pb4Rf.b/XI]C#D]Y##P(xJ1x-,Q'CO=j1'un$$icm#'G`k/Mn[Zx6_UiS%:Qr_,P4-5/qC?%kfa37/04m_+vNtL#RML]#5pq^uM]A9l9I5tQOIbn0rVVP0RUeS%]?5m:3++p%\"\n    \">A+:FvqsG]g7OQ/CNjd*e3Q2(Q'^:/xe1r)9X-0))jVnJGQsPA(L(]b1_Z[$:HQ[7uDC>$KnW9%Y_;`53$I<&';9Ygq^Xj(fnDQ/5rTN($jqPMu+LS-Zgi.08Ufi'Vh$##A$)&(>LugL\"\n    \"B&qR/D_pfLOII&4h/qR/v(A/L-n1-2NnFI<e3+l2qdhr?v(4g4ohS883R7q.$6K-)v/9I$gdp*<Kil7:Z$+rA$K220pK[HZ?MDX-FpeX(^>wD3*Mc##d?KJ(vAYc2J+65/4DXI)[(sM0\"\n    \"J6X=$FgU`3;nC#?PX1*4HjE.3Dk[s$fg;T/@J,G4#MsAFYC.$T?RP@tTGS@tevasM6^e.hj5fL^/PG^]S?q7JRCe`E?(Vl/:`Yl/ewf$Pd=eM'7h[i#.]cSDOsT@t_0?-JgTV2fFjL>5\"\n    \"CqvDK.+CJ)qR-igqHRrubpBXm>1gYm$RbOodCP##F.YwL;fr:#Ee[%#Nc/*#Hsgo.j>%&4F-p8%7:*M-g*k@:MLP8/lD4j1)t+K.p6$`4_/._,gCF.)Ei(?#<K=_/g+r;$-U9Y.4t`a4\"\n    \"[n*]#V=SVB;>v`XSGMLcKa2DN>HLo@0Bjg(;-g01gpmP)CL=Yc;EOA@%1OX$KpbY-Os?jUrU,V%v@ZR/u^KrHxcvT#w.TiXUgoP5%k#gas_mP.<kDAFWE^mp<3cQuV^]8(JQf]%`0lMi\"\n    \"7f#(-1#.L(_H@-)TnE5&oknem%5Ve1P^(W7ePH[M?`7e]OCY;]Z4n0#B:gLpi)m,)8Ufi'xS:D3i1Vn8;F_#$UE7dD+&:B#Uq@.*2oWF&iE,7&#-xh&^$x+%n]>##ceYw5cJtr-cs,<.\"\n    \"tRt<6[[g9afMMO'<7Ha3v9p7eL3^Q&o;Zx4J_@w#9WlE7o&Lv-o5@^$aK?W.$,P:v`32#P<9#)3:E-)*LW1,)f'4,%x-<?#F[wm/O`&02C.<9/%C2m$)MOcMuKMH*IHuD#J</X7bRbh$\"\n    \"s<Xm&?hNt$_)oXuv:#nAK6#j'G^Kl&^OOgL7TI%%A9/v#7LIw#jr-['pl@WV@@6mA[8PkV5FOO'8W(v#-gotuXUAO'DYaP&Jrr/(Q76$&^9*v#S)v/(wih?'`#CX;s(V$#)]$s$T6###\"\n    \"eUPe28pm(#HJa)#;/:/#mttM(vQj-$S+EG%YclR*xB8N9t6lR*0rv`4kI&^/FMGf*96XW-'BxU7$li-*o7F]uguRH#xNUnu*BdW-L`NR*L?Xe$vxe+M9+5cMD+/cVDG_8.;4K-)7@W'8\"\n    \"64cA#5EZ>-ONIC#uo<Ftq;BO;#3.?8Z+CH#B6<X(IwuA#b)`*@u@7Z7obA+MfV@`ar0,X71hH;-e(J-)#2Q=lt7o%uOo.jL#iZca3B3g;Rk]*@%qJe$I&(<AT7^mMXD.+#&5>##v*FI%\"\n    \"_$q:#mom(#@->>#cr2@$'FA<-SuFo$iekD#-Iff1i%>c4D8v[-K)'J3*hlf(f9_Z-]CI8%i_xjK[[jv6uU>c4sVmX1Bf?MT6Kt[,Vf'716`[h(h/Br$GY?%bZGI-)@9ax?n6F:8=6ax5\"\n    \"DbuA#Z?Ig#V.xJ2L_x-<mTf=-0&dT88D6^IjNLaP$X$M2XgQ;^NDf90wwaaaNtAi'Yniq1Z/iR#<*5N'srB[66%@ZM[KXV.FvZ4$oaM21@JFm1l)g#@v?KM3<e+)P4%4L;nm0^u.iUV$\"\n    \"wJNjLs&B[#>f)T/;@n8%Va)*4(DPjLk>L&72l`^#w?uD#[eX@$ppVsudRL3;kpE(3?t0>$6=<5&:=I8%T3&e*J^KB^EZHG;m:u.UMwF%XZ[of%,7)U%N08@#JH5j'>LeS%+[Zl1CjjG#\"\n    \"0YN?p*HS]:ILf>.DqCP89<hc)^cX;-2MjD#7%x[-4tFA#5T:)3P83x'$RHw>K?UCca?.J:Z_4J/.ltN+]VSG=QH)F=xR]['ku55/*Px6*/1_>$>[-_#-`MouN@`Q#*v^e-N:kL;hL`;$\"\n    \"57`h3.+1^#,SAcOYm('#1H:j056oG;[8DG)OA2<%M;1]&+/`5/sk$GX)=K[>+o5seF8][#R%n0)$ix'41;MD)co&/)WQ`x.VIvG;>DQk=,7aW-vh)f46`j>5Nu%5D;]Dm&L.N'MU@9C-\"\n    \"]?KoL`?;,)1F_0>^@[5/(5[0#it7nLk_(u$cI=j1Ci%&4J]d8/Y.(@%S%>p:J17%-OvLG)2uWj$ToQ8LFUX/2+5eW%9%x[-=89#,(A*F3q.Q##+)=o7A=%<$&]v7/1To2)_POS73Q$ca\"\n    \")AVq%Mw%/L[_v[)1&@%b.l4AuHa7:.]%R`aaI=Q/h6==$J'bt$%vWS77GxL(&GF+*w=Ob*8osILP^S?#7#jZu(Sf@#5C:B#$wA.&`o-x-P0+3:(O6$v/i8e$*Mc##m+3)#`F<<B)X1)N\"\n    \"xUJL(I7@W$jpB:%?isf%E.@x67tgfLHkZLM-reD*>tq^#O-BR;RPFSe[]iXeEX'1p92hlSNgAE+apo7/a^O]#2p4@'bb+/(ZeR<$6*no[qq?1M=>U1Ml0S`a`ZAr.<XY;&ipZd3diTT&\"\n    \"L+k[$@=E_&1%iw,Rkh58%RF&#M3O2LVcK/b3kV@,Zc(]05XKb@@hsPM2.VfLFI8GVRmDGV+:2X-*<dq)mAn9M>@6##-hi<%U7[0#avK'#TG1@GC5G)4/vcr$CH^@#,5Rv$g&?a3.PC%S\"\n    \";:mp1J4@]u2NVE87mV)4lKxnLI_lS7#e$YYd>h>fjqBj$S>1T2&idh#WNc]u,VoH+/^(B#dS3N0_HDbA:lD)%rNHAO0T-##%8cY#T6###'g#H.jAqB#WbHq@S%C^#A(Ir@unw2LxgA@#\"\n    \"B.$lL,cu(j%2q=#Z=9G&-g-@'LDU/)xP)E-6+:%/lde##-RDREWu$s$TekD#$Sr<-#D&n&O.9#oU3`H-3Y0wL7;#gLce6b%S6[0#-Mc##A4i$#9,>>#@BrHM*6fX-K1*(&1=C^#'tn+M\"\n    \"Q_Q##LW8e$.CiT.OM0>#5N_]4$>G##&9X*%L6a-$O<(v#K__jt(5[0#>aps-l=;mLYLo8%H-p8%$3iD3;kRP/jUKF*DxXI)$uh8.6WPA#AD;-*uKU&$?\\?EE4;R9U%Tm_u7]ht89:JQYJ\"\n    \"1sA]<U1u*4Yw.,*vcBFE2.iP+DG@5Ga>Jn29dOM0,l@o7fS'JI^.]JY<>Vr%wg66'UUTG,ib=>B=OYc65w.,;^M.<$fOkr?CvR?I$meo(]ndY#W/HAY#[]/.+pm4A):pV.n'?vA*]rB#\"\n    \"mE'>.K)'J32J+ed4i:8.KkFqIX#h>$+j4s1VK=YmPa.E76S6LdZS(EM1+B/LlZV_#,Yc255Yu/&@o;fnKYVqVq3n0#9m+REafUV$^)V$#Uqn%#nd0'#f+vlLEKxV'`ksJsw*ZV-4n,/(\"\n    \"*9d/(=SM_&'8tM(riC3=B'iE4k&B.*<GIO'GTo$,N<dQ'n7OKSx8iOS$^]=#3C(ruU$GV#AuGV#Pl5tLO<F=c9C8*%urEFtD.t3;;tJe$vXr5,9LQT'(n8n/xhg-6L`i[bp@XA#XV4I6\"\n    \"(m%/L9q2##O<sbMQC>,MJ4$##<;.2.2E/vLx`8%#>FAO6uiWI)PGUv-0S<+3?_#V/JI]C#-<Tv-,TD<%s8Mx$+jZw'.W8f3j2E.35em;%s0,sqx(M>$x/#SVO&fQ0r3TF%'eO]brCEQ/\"\n    \")rtlA?xaU0r1tLBXwk*faRALVoZCL#nM%g1.noT(;90a<cN)&$ULb.G/FI0)n5@F%YhOJ(KG=j1a+*<-5w9+,lXF'fE(-)3glct`&=K'BE(*T/TUZ?&#)L%@sQlk-&Ao^f?VS/Lv7?8%\"\n    \"OJW]+aP>c`(1v9iDp%B#mn]0s8d3bNfce`*6g9<-;1]gsUG>f*l,>LM^/f)*c9OA#3c#<%tThhL5bi8.Cc*w$&Lj?#ax;9/HlF9/YekD#QV>c4t3Tw6K]B.*eo^I*wV))3f]6=.x1fL(\"\n    \"&7^N6l(MBSOG]>hr`?ODq,97;7Go/1eNFq%VM*u-+3*E*nOB6&D>gT&^Ueh_X/ID*AQkD%+Bx;Q-Ha5(>7FE&Z;([-`vF[0swraO-$_m&V>^p&;?vR&MJ)<-G@f&'<%A5J2/TU'nVVO'\"\n    \"IB-5J#Aen&m$nK(G#4s6#h^404=s;$9SmO(OYa>25O-.M^3@/vE:BO;#/t3;@4nb%<g&VQPj@@#c6_K21@pm&r5tD%_waaE.wg6&5<XX?(Rhk+=WB*<Ngad*tgQaN79(q%wqjuHOtFO'\"\n    \"ux@]0';.1*9',]#JZZ:Pw*m(+`MDv#5&r[#5r]s9fi?['*a`0(Q:fA,N'f:.rD*s@*tCm9nq73MAw`@,/(_j]PrJfLi[s`#MM`.L/AP##B^4D<3_+/(s5Tv-^@[s$@]d8/8V?x6LdqA$\"\n    \"j>%&4'm(?-B*'u$dfeD*cBB:%1TWjLDo*w$N63-*90Ea4dm6W%MWPA#ed,nuOFu%@;>l,3Ft[[#*JuY#2Yu>#$Lv?,M2OgP''^E#?/#b#umKB&4w3U.2fUv#Z(ffLT5YN)vYvPTO55cu\"\n    \"7Hk`,c29?Hk(ZLLGojhu?fi=(_h49%JFR8%:7[8%4u$s$VV`p/#%DNIYUE4OJPN>g&W)t.fnv>#R>0A$9%`v#IC@8%h?N8(ZGD,>D0uq;-WfB;xd2w$*Mc##wYO.#]1ra%Pc[:/'TfF4\"\n    \".48d;dL'N(J]3'oJ(XD#;_#V/ilwU/O-Hb%D,D:%-Q9.$%BqB#koXjL>2V2:>`CE4[C[x6kQ7lLWxSfL7FEN3ml,##uR39/P0U:<UMg'BKgJc*jkp_4=f`11Rq:3(@w3q.bCfI2NSZ'J\"\n    \"*&B;.8osk've<q2<rJ;65c8YL/Y3HHNJq=4EO#D#NS;e5TNT7/Rp7(>&R:X[N%R=MS3w=/&='i;rdXSBBC$pMY0m^$#Vj=.-,jILG00U%'t&eX`sxK:Zx@796K0@#GG,p:NjUX8V*@n;\"\n    \"SJTn0#X>`#<c]h*@)[++qT?t.m%4&AL2OfL_ow`*02DT.h=N)#aK0-'_ntD#?\\?EE40kDE42%Ap.iE8j0W[^Tr'/K+*rYRD*%pE(47HSF4J_Aj0dCXI)]::8.Hun$$IZ4L#D]rU%I7[x6\"\n    \"=J))3AXvq7AeVm1c.5s0FS&(4&phY$6&K9MC&JI*L%,6'EE0R/a&^*+EBo.*NemC+%2UH#/n07LZ7.Z2DX+1>s%Ep/4;@I2<(o]u31t3;:YG,*@-iwD$>kP#<drs%^@Yd3+ViS%0a98.\"\n    \"$a9X6)CS@-:q<[,.R(S:MdYj'Y]iIL]BZ)4j?7m8bHk*I9O=*6Sj21399;$Ae3-w7upsg=dIph;631H4f^>31'j:f$VB*f)NfDZ-o),##)UO2$I%q:#6,>>#kt,,GD7cS7'<Z=?dK?Z$\"\n    \"2Bfu*VnGqIX`f=%S6[0##&*)#1U5l1XE/[#$d(T/.C-$$m;?r%3m-M;=BtX?HxZp.n]#U8l@E_IP1?i()wO1:qBL_@X880`[grl8DT1Vuc7<l(#:#Y?fi_s-Kv8uJ32xE3;_%,*;p`j;\"\n    \"3S3O:UUU=`#P;,2Lo]nmIhYb*;oh*NYd$##NLQ##64GS7]b>K)m@C8.#ETW-:rE=(%N[L(Lov[-+O0#$1Qck-:-(F,?*vM(,p^I*S?<h#EWc3'Y1]JY0+SS7-Ye['H$&<A:i?;-Os(K(\"\n    \":uCv#a?H=l:J)^uuY29/%ZVI/75G;-hY,g)[FE4Wjo24'>O]9A;Mw;89,[8%A-re32Zr<1b/aC$m_>;-L@=X(JG:;$;EMM%g_fi'(sq%48<.J3h#Rl1$F,gLG#YD#kDDD3]77<.`K@+4\"\n    \"7fffLteZx6IS'i)>Ac97-Y3As(G^V:5Atu5IbI?nUXkX:i`Bv#^_b<6D[d.h-Qxs6-Z[#ijbmg33'd)uJG9]T4=n?83(9GMZ=Bg2+)nr:en'^#q^Z'#-JE/L]9]f1m_(/:PD'N(hw%_S\"\n    \"?lh8.V4i?#CT(T/:Vd8/K)'J3%lMDdCZBS/(H^@#DRbi(8?a`#X.g[uhdZJ(PKKY$JErL+)*5k3GU5`#WS<j0r]<GVZ_=h(-8Oo72bH_ugR(^u#MG_+JRHE+g.<##QlVnLF1->#6wT[%\"\n    \"OGY##4(,87w,ShLFV7I'c3YD#O,:gFvsw`Eke'^#HfAAua55o;krDO'YhPB#g'X1)Mti`@pnB^#1X9IDIc0^#A5/Z$V8f>IG7L<.,P/%bVEdA#hIij(xm.>#uNYk4C4XrL;8*>.N&)'#\"\n    \"SGc%&IVFS7>Ri2MN[_p7lAre3hcMD375^+4]77<.INpf1I9(u(K(L584F:B#b@efu5[&0%=^2edgk'M8Y(U^#EWc3'wE/j-7d,HO9^CD3X^388]f'^#Plb_#AnaT%wBQC+2=%v#K;)MK\"\n    \"l`fx$$4;J:J+65/MfXI)`R3]-(csD#uTJO9]SbA#?EbB.tA*W@trF3bu[NT/F?)F=&8P)4EGwRC1P2]-7:Prd+*Cc`@t;>#9t&CLCLvSGqY>B,e*@_HV]-%bYmE8;<878/m5I%fe0er/\"\n    \":f*?83bZk%NQ1p/86`7WLds*YDD#?W8+nDLj^XP<TF7w-$LCl:hJ>T'@FqT7D30I4DLb50x(GCHNjH$0qbTk$*x$##<]+?Ic3e##IXI%#jd0'#,Q?(#d'suL-?5V/n,wD*;]Gs->oq,N\"\n    \"KO^C4[[;R*Diww'HZ_`3_I^_4e,i*39aQ(#mVWI)C+TC4m*ZQ'._5GMwT(E4R#QA#6H()3SV>c4iB7f3Cv+G4:p?A4WF9a#nVe)*^$Jw#-Ovv$D+p_4/v)Qha3J8%<FRW$QhbJ*;=Rs$\"\n    \"eTX,24l(?#K/n)*/o6s$<8[8@=I7<$Vv/k1#o/a#Q?UG)IckOj4O6)c7v.@#G$U41:O<u-8:.w#TjCg(?-Gk0/nb9%VVn6:`Zj@,[&xC+/7dV&n,=@,cFal0?S7<.74&OT-:^l8,w'B#\"\n    \"XM4gL@I#9%`oU;$:rU;$_Y(Z#1VuY#@cCZ#?F[s$#mCv#c[rS%Kwh0(D:[8%vO,29$,_^ut:qkuafH/(:xrB#Oukv,39t?#B_*9%uK;%,&[X,28VS(4V6ub5xq:^+fS7L(eP-v$5^EJ<\"\n    \"cZ1Y.A-aV7go)m&lomC#Qj*%9Gtv?$NV%JLp7i`a9kfi'603a*571/2A/v[-9=F]-sL%s$7M4I)IU,w-[TAX-upVa4iA4a*`c*V%n&okBINIV6HuYuY>fdF`_O6>#du5>#dC6>#9+`w,\"\n    \"-h5C4lpB4-%3&dMaLetf+wt4:31Y`#qaR90NIaT/lXQ@)>`Ma,qx8;-RQjr4XuI/Ld?q.CXT^`3KlR_#M;^+4sf6<.peT,2[=@8%@I.[#xL'f)hu/+*1D]/1wHuD#-Tg[#YCh8.&gbKM\"\n    \"1Xv)4$2f]47YucMe:BY%M@`[,]&PA#lZ'R&Kw&6&Mg$-)URDYn4rB[81YVsAXl_+*vdM4B;w4V5BCbWhO1A1u?cfS5)6u9)F_&RCk1.N:8qJUT/*->n&2MO)vQbZ#6xUZ#deAYcj$N],\"\n    \"Hn-G*w=_j(u/JI*dgDi2skbdL,$fH*/u-,*l8C0ij%J4Xg7Ex4NlM`FIObM*0CkaFk*7-8peZO2Su?M*Z?MK(ZQ9u$l@OfLrwSfLU$WV$)8[0#t,>>#t?bCMhNgk$Bg:9/]P@&42+$P.\"\n    \"stC.30Z,T.m]WI)->pV-S6tgl,91#$tB:a#Umf;-%a$W%-aA/LhTILC,U2G31aFx%Ra^guas==.bcrg(s(t.3hKCP'k:8T&&OSw#vXIV8-*Id)j)Y:Oq'-_+Spr.3Ifc?,Nuk@5t9D$%\"\n    \"kana+SB4(5%_GR&B]&K2ZiX0L,VNa<&c)c+X`Nn)KR7s$<9uC523bB,_8A/3</T^+4nq%OJ$kc)h3pE@%n'#$.xST&K%Lp7DKF&#m3Nm'Yx2'oKewW-Lh;]/bX'mAId^5/]p&<A).-MH\"\n    \"#C^;InW>M9DDUk+Tl2%bfS'JICxLe$K/5##k7ig$.)f&#%BN/MiX/@#0q1,)X]$7,xAt=#)Zt`?D4^E*a)9o8(cL'#2Au4S76tCE4+;o8rFHrB>*C*#Nt]?0Xc7C#.NQ_#TXpQ*,J5UA\"\n    \"c]1C&L9Tv-Nghc)qfeD*oh$],o(TF4<VhQ(*@G^$phui9Y4L#,:fF[50*i,)VLpiBNLC2'5@#h2n*+x#tQD`+*6LH2%wm^$NmLg(F7=>5fPmk(D.u2(q%>+*XS.U%vDhW$:T8A,0=hp7\"\n    \"*(g2'ORlxB[Y@-)/2mW.(T***xBxJ1QG`>$q2nM5DDd40fNu`W(Q-a#N_wW$%;k*4Jp%YSgh$##VeQ##Tb$##G&e)*]?^M'vS5FYWh?lLu3XF3;o7T%?T/)*I>%&4SsY=$uV8f3+g^I*\"\n    \"H-p8%v/YT8llPqT#-BQZo3:P.JRAvD&GJ&,'#lCRF`t/<%$28@6op<N3=;xAia7E$AlmT'jDkXutUtbQ1;.2KVENE*uKU5/4EYl=f2$a]S+U,N@1J@55u*$#[h5'#QEa-$5@GY>voY<.\"\n    \"jBFA#&D0N(0-k-$Z;%6/%X5k>WgCT/EYE5vL*KmZZC&tuk`wj`WPu4&F(vl/1-u8#X@=gLGt5.%S6[0#)Oi,#HTF.#gY$0#<.*xBfuPg)D.[s$*_j)4l3qA$+Q?T.W`wv$&?pv-bNJ8%\"\n    \"[J@d)p`[D*?@i?#lwkj1w?vr-hF#v,/e&g1%GNG)ig'u$Pvq%4TeLhLgo+G4EjjbNSe%BPJu;9/Rf?K)aK7f3WY5<-?-J>-:4xi$V$w_jBs+A#Mc[;BWv7x.SXd[/v0j.ALq,/,C8O:0\"\n    \"YrrG5DsQI2&uP.)FAke)LhN9%vnf9&lKT5:?Of@#@<eru'eGD$<o:v#Yvpu$kU4gL.-%T*O6kp%^M)W%MtNT%q=N@$ZdYj';(0L(+rj`#hvh0(w%&pu:,ntuRY5a*_v.g6%T=a*,*-L>\"\n    \"jNfGG/[6c*-+D<-&v)D@u$ToLs8Mu$I/;6&ku2p/A6GN'EUa5&ZKT7/euC;$bq(F$JB+d;.'MLgWaG.L==e8%YhV20D[eW$pD-*3O$f8%wk+u%pb=gL0CBp&G-X=$ERiZ#@l1v#P<Ox#\"\n    \"WI_p$SYqr$)8[0#I,>>#R+&6/PDRv$vdm_>s?C@.dM8f3H+7X1'w3V7$HX>h%31'5l%>o7<Ha`#xZ(?#Km_v#SiDA+5<,A#f9oDSY$ir/:/8`$aJ)R#PD.+Ml]Q##UjxE%QN+n'`U18.\"\n    \"vsai0PL;aNGO%.M-fH)4]X1N('K+P(*A0+*944]-F>l-$p'uL8]?]A%rHtt$&xP3'cQSe$SK/##)KW-?7W-dttw?gL)6A:l?Gg=#PfjlA7YN-)I9pr-SoIfL)U#gLZ:;8%,YJV6kp^W-\"\n    \"o:U13+kIP/;JjD#U%V%6UMeD*.Fq`Na@6##c9JY-#+Lk+p6NH$kIW`#f?eh(ZB4V.KScF`XK6g)I7SGV,AGfGg5%[#JfUxPpZtl&c#?ru`,r:.ggbx#ar5]kro6U#q++T%7q'8,1bM)+\"\n    \"f:C0*?AbFNq5v3'8w+fu'h>J)Kh7.iqfE>,_Kqo.Oufi(*GKB`SAX&#03>k-^,p*%bkfi'lH*20cHCFeZ9x;-[qT:^'%ZV-#F;8.tBo8%k.ca*iQTQ/So(:8pHCE#-PNh#ZA74'&@_g1\"\n    \"GX3/U@@%P'9/8b*tQW,8$)q3(8vAg4s.5Y@a5,@#slZiMP6S3q/4K-)Xf?%b+:hB#WG9J'P@)?uE]ub#l9M)+@@s/40rACuO#[Y#DQk7IZr@/L0/V`3VB')3wkh8.81I20WEj?#`qi?#\"\n    \"u^/I$owkj1YS;cFX%pG3cA#C/L.7x#J0uJ(8oR34;KrL;`Z7duo0@B$v&Dg(rG>B,U,5=%,qkx#P6)B8#-EE#ejFQ#Git6Lxh0]Ow(3/L##'bu%@IF#gL$7AnW9s7.2v^,*/<P0o>*#I\"\n    \"(hf:AmW2>2%Gch3W7Zf_s<J^u@O$##*3e'#Zu^##bg9D3[g#a3=M-*4MiXI)E[TfL0jqJ)QNv)4^D/s6$F7f3s8w)4+gB.*jPe)*'@`[,4JY7(;4</D2G;mLmu9]7$)+julO)132TwV/\"\n    \"c9g#5s_J)av'UA?FOUA>sHxK:Eu_e3]:oDS8kvR0[pBxqM#eV$9?pn/%t[K)MS0xt:*+tYi:&##sVo9vY>IW$#v7nL,:L+*@Cr?#Ws/028Fn8%GPF/MCu;9/hL&<7C4NT/HM,W-qlhe$\"\n    \"J#[]4J[R1Mw-L+*orGe6jt=Q/1@?i,t26K`K_RA,A'D:&)5Yv,c<D1,[8DH2Cixx,IFk*07,5DO%<&60mE`L,tv=Z-k<GP45O-.MY<930T(uP0OVFv/,M1w,d6eS&bFf/2&,###U(h##\"\n    \"Z:;8%lp2GD&@b6/x?7f3hPF/MZ=cb$jND.3vZQC>HLXLsPSd>>#6Qv$5jr%.xb-x6xU>c4v'D.3jpB:%n3,W%X3U:<2b0o,[o/s9MFb4'Nd1b,E2Z>-A9s:=UHWu$+mTh3FAZsDJiK#$\"\n    \"E0>PPFSD16$$R&4'P,c*$M0b*A0q5'15-=7+<J:*g^Y`-X6?@5p*xT8-:Ih)u8Z.+qh1b72u4S&3T1iD395D>OjO59@2>o$.KIL(njtx#b.FC=KuL,NbfprS8RO8&sX,87A)'##Zax9.\"\n    \"Gq[P/QB%:/qwkj1s:Rv$m&l]#926F%dov[-[YWI)ku/+*LwnU.2r-x6J6G<%Uw3XA[K]s$#T0<7sS(h$_Pc)47%x[-^:/T%4a[D*uS-v$k&B.*t'[>-Ag2s/JiqV$NmdQ'b;eh(HkMj9\"\n    \"2hF^,cY;.<En&,;bt+T%:7+*?SS]R#b(^:/pPZ=;t+j76?gqgPiURV6JB?>Y%/IWDT$CFW5ha22H'S9.79%P'-opF*.r=)4r8*/Ld7%[-1c:Z#N`&i1?cZ8/;Jop0N&LM)$RhL;-:]p.\"\n    \"Xk6J=4p&@B&>`^#WZ[345FipThCYnCq@mx6%/NwSO8f5Nm@gG=hMn'$&>FM(wNbw7/OO&#D]458kM&A$PDRv$=?E1)NDn;%&3m;%?;Rv$j9K;g)']t-9d?['1VKF*@@ni0BxF)4#,]]4\"\n    \"Yp?d)4`ms-uxDK;kP1E4[4pL(Xf(T.nG.)*;`Ys-*c7+<B*ADX(d5t-p8;=8iPq^#OC]5L$%s-4SiJ/sTF'@8p9?v?LX?6sq@I;8hTa5_H57>8Mbc;fT12&&Y5###>8E)#?->>#o1TV6\"\n    \"o^54iego8%B[e<$@]WF3tcMD36cYs-xm;hLLMp.*EU@lL.4F`#;p_/1n,Y,2p;Tv-msHd)8`Ys-j)sHMmX?x6vU>c4-].t'vU]L(jptX$sOtAunlbR0>S9p7%r3j14=^Z$*.PA>u@vjt\"\n    \"L.oC#'S$6%]XGsSn.LQ4Zb2(8)9V*4&7X1;;CZS7E+>C:EI7W-(,*T^gTZ)4%gL>$Nt*g3KdVa-R.;aYo%I;%p)588xMF&#sL'^#=h&9.n&U'#t@^)3ITR12tLn;%Eg$H)ZH-)*o3q+M\"\n    \"D<-sI*^/]$c,g[ug'1.).CNl(&_Np(QPt(E:FGb%TlX(seF-##`(Aq.U)wN+ILnGHTfQX.q#acuI01lLX?e-JEiOwTZo(bRl5Bm'e@V&04`p>,,]WF3;(/+/Ne4D#47:d6X'/W$<ak?B\"\n    \"/u3e`m8p7/[)S(s$_6B#L^;2'(I^MCfb0q`OGaEeC/GE+Zs;X1&n7mE_DsR'KiwU/@<]GM1K=+33B3I)RJ))3bO1F*-D+`S@^k<Q3x+c-WEf(SI@Ql(W^4j(N<2Aud](12&@Gm':=]:/\"\n    \"x)Qv$I8t/Mnf%H)V:rBS[>t,'70XSR5@0C4QPt(E&7B2C:3b8.[Tx7/FoHX-J3b%TV####'&>uuUdUV$Ug1$#GY`O#x:5G'26Qv$F7,Q'`AhY$lo[:/=X^:/a56N'wC,s-Fa[iL29`T.\"\n    \"c(4E*pO`S%35Eh1-lR_#-[X,24G@A4xH:a#+J4^4UH()3HiZx6348C#*Ij?#+j+G4(8o]4i8``389ZZ$H'5N'hCbI)^%<v6-Q,PMpuXI)P4[s$h9=V.Od5N'Y*SF%l'(L5XU#I600w)4\"\n    \";Rlj1%@/O=@Bg?T%5-J*4%pA$ESi+?GiC4)5NFU.`qns$L<96&EI<p%3:Cj(v3]W$2vj[th<E6/H+O#(`weg:I23**B9^q%boio&eaTq%Y::w,B95T%F<pm&Gq/Q&Hw/6&1*[h,AMTb*\"\n    \"3Khm&D%I>#,P1v#0x?s$7`L;$JAG#%Z=,c*@C<p%w-W[,(>a'4V.wB&7L39%0JuY#HY./2[ZG[>Kuc_+;9fa+YVsa*9CC^=s9+9%0`:Z#vg.],odpQ&V%;q'MC@W$J0OT%m`q&=C:mY#\"\n    \"J<Hd3'U^u$x=[V%1fhV$`i`o&_HKQ&SMc>#`3EU.`D)o&&@D`+8L;)+p7*mJM<Bq.E[a5&X:Nq2Tv=_/(nkt$w.]H)C<(&4hYMO'6uH8%L,S9Qp4G?,+69;.wBLO+<il$,8EON9HYf1(\"\n    \"_E8N2Wgpdmqv_K(lYRL(]?vZ%:UDO'8`1v#0GcY#>91g([0Gj'Shrv#/DY>#0fU;$Zw041Mj.j2k3=t$b)F.D6xQ8%5VY>#LqsP&-*Dc#C[<T%jP%h(49FY-/Yjo&3e.t-Al_;$=On8%\"\n    \"%av3'?I_j(bG.P'o$QG*wH%a+gQ':%UFhk+ENWV&[Ts/:le;b5l9Ft$eB'Q&`T,T%gbe<$5iC;$:h]M'b15C+aNS[#).mZ,(d'v#89q(*nYD/L?K_c)J5n'$Yw;?#g<.(%D$5D#W6LG)\"\n    \"]::8.U.`$#ae_F*Yb@W$:F9a#=uk,2?x]d3P74`#Gx)#/tkw,EqE->YliG`j87(WP,cxX#H-eoKoX`ZuZqhSRs3%L(s&e8/e/Yt1Re$`.?uRt1E9KN#K@p/Nml*r$GJaS&0+K4l4*As9\"\n    \"7####1VjfLe,B/L0)>=%I8W]+4fju5j,KZ-WR1DNCZIb'*KcrH-7#H3rLvwPaeH##$#nILQlK##w[5<-&cPW-6vG+<g+2S*G_%L#s.o%uTH_H%XY29/Y+&''P,>>#C;.JLe=U##r4`$'\"\n    \"gC)?#sr$TINT9N(cu+G4&=Qd2)lcw,jk=6']98wuHZ1G)995O0VDd?$BJ,]u#9:P0MX@@#QW+A#lpPW,tC$##x>ap'^*[##=Q?D*nsx+2ESXV-G0kqK0h6g)(=tH?n?lD#]_G)4hbtM(\"\n    \"GNl'@jLN`#O$#Yu[0YBA8Dw;8JG3F/C>-H+,6`+MYPU=#%VclAq@YS7:7clAt^S##Kq+Yu3CIq$U+kZp;ip?L/jpquh+`B8-I3'5-`(FAV0N?REHU*#f;d]4%-YL:,.VT/=9#p%)0ihL\"\n    \"G*tY$'(]%-F9@['`x;9/-JQs-7X(hLifps7HCk05E9[Z$o42O#92cTr?-g[uZM8L(p`6fUp(>/-oML^uL&fp/OA_M#=S7U.i&-n&[auO-W]=Z->5Mn3J?iB#KeMT/j:k.),FPm4nnI^P\"\n    \">-YX$mBp34UQ@_JsL5_J`O%%#:K9-m:)S/L:hFJ(8f3>5c+M]=)6&##TFq8.[ge4(]u_8.4jWI)aMYs-s?$gL[Mvu>%,a[$`bLs-;va.3YCl;-Zfv@-%5cn0RjDE4us3-*s9uD#g-v(N\"\n    \"/>E`#Z7g3NiC3*%fP`V8D&8/Ln%fOSKqMd)%T_QCRNRg<_gmn<hCaPC*F.g)ijs4SOG]>hQpoKb'CmV-)>2:D_7W58fPc8;VMlQV=n'/LCAS1<0v6n0^+H`O3d.jOmaqOCJCQZ8,kCo0\"\n    \"L*rp/Jl$bHCW,1M&d$jui4.X$'bgFVC,dd$gqtr.;ViB#N(8>-XIVS%H,###pb=mA:#XV-%NNcDXT^`3GH5<.ogK>$vkh8.HweP/L5l%&rA81,1r0DNC4MrAj.h#$/&EG)iR,3Da+mp8\"\n    \"D&,d3b.-o$6[(f)6V]C4S)ZA#a_CofZS(_,er7-)DE)n',(2w,2x^7fV85',hgb48ROjo/mDX2,TX&50b,4%$463m=7$V=f(Klc>;9@uf7`Mt-encjL$-D#$,rc(+D-6>%$dC_&f;5',\"\n    \"f<@uQW95)M1-W`+&RXjLMBfx,U<MBu1oN%RDJUs=qf;D?:mNGPT=?>#xbLP/0JE/L>u###Wb8j0n:gF4?W8f37eX@$?,J-mBuQA#,=eCVClimuxK)g#o<%'VQXWS9Xa-B0$Wx.LWhG8%\"\n    \"tqYX4$YtT#xlx+7Yd.@7kWaY#9s-JLw#H/LY+pu,_tu,*:2Cv-=jQJ(j0w;6)_Aj0;(m>#(VTN(B6J;Q]RCht6U9*5w%6H+Xq_`$.w3V7ThbIq3MaIqj3j`?).N)$hJ9A9I1U^u+3Vx=\"\n    \"GG_A#P2]nL'a88%EA.JL2JP###On(<?Mk(ExIf(N$FuU@;?j[$Gq[s$]1h8.u3A8%MQT:%<i/gLf/Wa4%[*G4+._C4[j:9/c6S>-QS,<-n0OR/pxJ+*a)YA#3a3gLDceA4ef6<.i#[)*\"\n    \"a^D.3gk;[066oP'(YQH3M;A(4jHSP/[j.gLS;MB#m4K+*1rSfL^h?lLhx`v#gR+T%wfkI#CerV$40Q0(9[nC<V(pM'9wrg=noxh>G;#NB5i+m=M2<6JM>Zm855<O=fuV20j)peQeXaB%\"\n    \"b(6Y%T0Ja''(50LfA8#,1lo-3*3=q:R:.Q/X;&l1UI&_@<63D#l5%Q'HXgM'/Jc>#>>^xkBt-GVa4xfLXWcx#Pb.%t9*iZ#pa,T%GwJuG9Il2(tr1?#Cce>#`+4FPOE/+>YB*54Ww9q%\"\n    \"wV.3'Zfv_P>nw[/4am_P(;SC#C<q+M-Ks5(_>0CO@Q=%6Il:p.jaRLMO&CI$_39GVK(6K)xicx#<V1v#0b/^#Iju@=T3PZ#?_w<$=B#i7JJc.$,PUV$#&5>#0GY##e_lr-&a:D32@YY/\"\n    \"n#:h$rq4D#b/v[-<)]L(?F*?#poXV-P+Kq@q%g*%7*0fNLR]GV^?Pj0cb5'5V2UlSt?XB#%_lp8`**fh'F,cMqR8S#mxW05W#xd#'P5Gi,(_>$obT)nqk>;-&P8GVl%0I6%YP`u.Hcpu\"\n    \"P-8luHbrO#U;)ku75]Cux;dl/(qkU$V&Z<-49s#MRR_e$su60#2sgo.-<Tv-2R']7dvf@#9i*x'>$^5/J^D.3E@%lLa0`EN%Q8f3A.ikLmc'b$74VPNCDMXG]%V0HuJRW6Hxc>u;:a3E\"\n    \"cepS%I@Z)>6u@U+LB&*+]bps6H()Zu8#@M=UX7293DsrU[nOvGZ?gUG/dum&'*bZ#&Uk8E#a^_sI4$H=mM$h*L0&a+&`Ok+>$F?#P+SJ=/DBC-vhF$'TBYc2iH%##*c?X-GOFb3J?gf1\"\n    \"]ucZe+I1N(j%2E4k&B.*Kuiq%=WU;H6TfI*D7H>#Ot]=u'bK<L(ieRnp*^<?Ya<3L]/8$$n=x_u%Nx[>*f'^#,]JDtr2IlL;Kl'0dWe`*>(t.L&A3/LnQE?#Y_.[uGLbr.lFl=#Qoq'&\"\n    \"G3GY>4aT/)70A>-#E`x.OR+onuTl>R+&U*%S6[0#t]wM(.$Imi`X'mAl0xW-=wuE7rMCp.Q3=&#p79u?2<]@>v7'#(fe<?'GbHc*<G1BO?J>CLNgAE+xUkA#*bTgL#K?uuEhUV$B;4gL\"\n    \"/V>&#,pm(#?G4>BOsSk9=VbA#Q&d<-a+-xPTwo3%rl$SV#u,Z$+uMQ&4c[oqU/O_OcbwAM?7;J#aaPs-Ej4u*Ge<W-UueY(_u<x>](Ba>d-@uuvf=q$904&#VC,+#AZO.#OQUV$-<Tv-\"\n    \"7eFE,9W4Q/%Ue+4.rGg)]H7g)]/2,)`Kv)4CGI>>xI.U/stC.3qYVO'?K@+45CHC#m>sI3w?lD#%l2Q/.2HwPB;R/(8)O1FZK9E5+Yjl05_Ld2V_Hq7Ax_c;I:(a#Cd^,2Ic;C,8-mA>\"\n    \"t4NP:dPf:9>[45opp,k0@whI#If-n9^/klo_p@`&V0Mi<G@eS1OBDZ%'I690ng,&4>Q.#'OJP2V607(>q)'I*x=$&6*GOr9d%Lb49R]@bAMN)3Y<xw#4n]<0a*aK(iVTgu?:imN7teV'\"\n    \"*+jf4eQW$#i/f-#mp@.*miFo$dekD#;I9u.w^v)4;:=]-[9..MsqXI)dJ?C#GxN#>72h#$.DXI)U<=W-cs<I-2,XT/jr%&4U=YcMIZE.3SP,G4/Y<9/*k>h((pwn7W%b)<q>EG*a9SL#\"\n    \"g&RA8aXYN'AlGV'^&>>J`06<8>JWNDq,OW#[V`H*go4h<UXNgGIUro'/8G>#dl4[,2G*N1g,VP:)oUR1sL<^#HYUHMZc%T%WO,N1lV1BL;AeT.Qp;H6Yh7s$No'>@:%_S:Qo$N)0bowu\"\n    \"Dp(cFj.F=.S4Ye))jQn&^mjaEh]ms.i>6j:Z7ou.81v_+PZ5s83Z-&##YAK1O/:/#6@'02kiE.3SLCwgoE->%#oh8.hp?d)$`TF*kC4wp3H+wp<_2j1oB=m/<X_a4f4p_4Z9:X%dF[,*\"\n    \"rF-E5Eu;9/V5c)4aX<9/R@fT%R(B.*@1OW%5b$>6T4,^>@2,&5+Q@;6kl34'9[Et$_oTA?uf2,5_a=U.`jPj'ENU,)8*0X'>P/^;cMr;$r2a$%K0>N'hRpB+J:0LE@E3iH*gQ/*cp9Y$\"\n    \"?/6Bt@^[h(Z7ub'^a0^#-WF;$2Mc>#'w_v%uC.tHC*^Vm+<46<vJu',A^f&,&eR6Ujx/j>/TG:.*EcY>?7%[#vMEa*AI*t$&[Nm/st0`N$/jn1ML=A-Bqt0;*PZRUG](:+Htc9MEpOC.\"\n    \"-`($#wq>v$8C;a*HsZq.]S8f3(,j4DaJSF4GLm<-L*<wP:un6%YY`p.EdCO'6')_fDGF$g_%%5+K&L`/g>4A'4ZvREr2.?8*K+<A_LvS7>Z4XMNH#W-E`dC&+dqC&>^B9R.SLDO5Ox(<\"\n    \")IX2'O5###*[qJC70E%$QPW]+rgai0Vh$##UpKB#%dEa*2It/1V)ZA#pwr?#>V&E#J5)E3.ruo.l`,r#UjE[tD2*[cRXIs$#D]Dt'W(e,Ac1p.*&K7cwYl-$W$G@NGiD+V+uK#$kBn]-\"\n    \"CJi-66([D4lFDj(7?^k4qrJduT=*>.+i'PA311^#FiGW-#M&q^oU+l$*Mc##K_R%#Je:t%*2tM(#Cs?#A));?H^BN(phQ5/h9qk$G=g;.8P%OrdL'N(j'U&$MPsD#t<7f35IL,3sZ(N;\"\n    \"7,=ODqp#/LFg/^br1`XKMaAG;n0%X-EM15SdnwIL$'VY7%biW-s9w5/CPC;$iTPZc1,sIVh4H##(KNb7lE(/L;nuE7ThL7[r3;L;:Xv=#adBq%=@q(E>a/7MXnH>#TcjE*t`CB#cHf.*\"\n    \"h/+jLgK$ca']%3:^R$j:T+WE.i(>c4Z2QA#It*mL/-8C#$OJw#$`^F*ZHuD#3`<9/d@H,3[p+W-_*[s0#Pr,%gZFx#i`_^#nsFU.MSY##cGaBgLxD2)-8u*EVdL[Dv3brD5OKs0<`fV%\"\n    \"94.s$8N5TYY&iRElJ)U%ss`.34>:lB[YwouU%]H#+7=*$&U.dueH0s@fm?d/nbMNSm0%h5v$a_8V/=p&+;&x$;S5#@h3B=MQ)k`64bG)-`F<J>P]+PA1@)H#]0aT#xn(9#kW@4V8J&4;\"\n    \"5Bo3knp7f3d$]nj63rpj/C;/#1RHo$#ba.1p-#01>018^,N3Z^)d5EKE;#l;S*X5&r`d*3-36mX*q52MuZ9(4Taci*gJ2k^^caT%U0;&.3K=D#uU-SU*iarAx4XmCDSb5&041F*d>8>S\"\n    \"q_E0Yqu:#.@Lvf2rNm7:pPI9C7ca,$Z3*5#YX^`N:5p%#Y]>lL+3#V/EkqR'(QtV$07$`4?;Rv$Y^D.3<QA+4_TIg)NT/i)3tLt%*NAs6lX_Yu]f$^+B?BoBQbu^@v-*%S&e$`VDaSV?\"\n    \"DH7rLX2mf(@5M<&@8xM+po3c3)MtIdbl^9CSVRRlkAa'/%pFf#2QH.'h-T9VMF%$#S#48.sMuWUm:M;$^fv8/(S/C4]NeG*#UKw1eX_[,sq-x6_pH)4W2FjLJ5>f%N,B+4dcVJUaN`*g\"\n    \"ne5<c'+;S#=PbY,3qBD[fw#BJOx6fO;58v$9[Zl]h95<gmKAdgeS7puB$i$0/-hB#-N^laQC4WhK6xs12AO@.xVO2Me8vGg'G:;$>X`#5Zj8e$/l:$#l,_'#a,>>#X02N(EV]C4max9.\"\n    \"lq.[#T;i`3_gp_,XkZt-_?rJ):ce*3NU,d3*j,*([5>>#+=F`RTX&[#%QDM0YH7^K&Q-+%E;;-ExmUBS=h>K$Kq/N/QTDA+;s$;%3kZC#qkB`a6UAK)w);;Px381<g01+%r26_#LGC@-\"\n    \"$fc8.8UXILRK`>$(f1nWdRJW7Uf./Lu,G3b4]8jK6d1e35IL,39:%[u.8?1M8gAE+o^fx#2D%q.aXQ@),5r<1F),##fP^-6Ds%.6=39Z-bK#fE.1-?$ap/%ucI0=1%o9B#SS39/WS,<-\"\n    \"8?,1NXlj.LCQQGM(7QJ(1d(T/^R<#.SC;mLx0(TMU>@?$V@kB-)rg%%+;k=KgcfF4p+dY#wHSvMLZ?MTZvV8/NOL$$NV%JL/JE/LbUU?^k%$##Tn@X-.30r.B%'Z-0_c=(SxolAeH]X$\"\n    \"g7Eh#?7AO9Q.3@$MV>C'fU'mAb?A=$#-5wfVl&-#3lBw/B_UV$qrC$#9qnr'Vtmq7QRNpBc`gs7cns+jxYkp7Dwbxu054^#A%Nk-nMg=:q3n0#H&###Pd:RW((;YP>c@I-2-e'(Rqwjk\"\n    \"(&h##AZv%+Ca.:TmnG,*tt$],>J))3%[*G4PCGI)7x68%b;qB#HweP/nqkj1.P?W-Pvd].ktU91OlAONM:oP3l]8v9Pb./:34dT:gF(?&XScG44G]C4,3/<&JY*/.qsIl;4K=WAD997n\"\n    \"ew,?8BFA:/,MN024OGR0PcSB#7E[S3f31?%PLUj(P=+/2qSv#+osZ/<n6i+M8X?uu4eUV$=6>##6sA0M+HuM(nw+gL>cv)4+gB.*c5J5B82/=%qH@X-vx?C#fgNv6JZm3+,=ucu;oIH#\"\n    \"3jDA=O#Z@CnGO._`OmD>OdJ._(5G>#WtOO0h7<&Z.vW1u(x,V#dqbWB$f=<BpumUdn]0CIB@LG34oguPvwOL2<Lx'57<8hPv'<<-$v]<6?rq;$_o;T/kK(E#eh_F*RtC.3qX5l1q:Rv$\"\n    \"sQWf'W$9Y.MDJ)*sJ`AfPCUKZbYtC%k%iC&=h%K:@YFn`08^IOaapv]nc`xeVX$REhVH>Uhnt5$[)Iou8?@dQ(x5V%nPE5&FeTt1w2m34Zi)HOWk5-&HL6hF?s/RW+lj]bsX->G]n1d*\"\n    \"Jm_N0$d(T/qiWI):Q^A=`W&w6s1'J3:mnD*f.K#5N]R&4'n6^$KNg@#qYVO'WCh8.J-xP//@wmLQ#lU%KsV./u^J+4XS-E/xD;MKjW/[#P_w<$MEtx#v.Oi(994',ZZpr%lbcZ,uh89&\"\n    \"`,MK(M?^M'x-_AR^AUlS>WlRK/[L*4@h7DEetEdE0kR`E36Do05oXC.M-'u$'rd2(13qE@rp5r%`mvE7Q-mgL9vg^+M'oS%dA:g);VDqLxpxjLCn_<.xVii0gi8T/nU,Q8$/s<%S%PV-\"\n    \"(ZYc2Rvs+;@;@K:;a21)9@&s$<4i?#OHOA#Bhp:/?<oDN3VGO%vqs9%:2Cv-a(Fb3Zl(?-P08@#O-97;:#[P&/%5Is1Hj+3OdqE6KKZb<m$<1(8#RQM'UcRe%`'^#:cfbO7]JDtnQ#@P\"\n    \"EZHG;3uCG;(.9GM^aZb#7u_I4dADO#LV:R'/]S+MT.xi;t8,l;e%YHM,ku7eCpaYH++L^ui=^[k<eqU#Rrb$9ps[sus<Mu4%)###*Pc##>?$)*`-%##M'As$,R7x,eh$=%[cJD*n0kX.\"\n    \">^?\\?$FG?p.;@n8%tPP1:8`0j(oHRA$+<4euO>huL1Q7i1FJiB5t_,T#+=`T#qkW1:=96Z$U2P1:L?'5qU30SnEC=/L@tG1GwAwqA&g3gE8O2^OfA2noJnK*>tI]L(>?Xo(tBWP/?I&q0\"\n    \"L,[TMu`/%#MixgOV.Dl-P&N3X=1T3KC;cA#PibV%sg'u$MujOfw*[9E*PWv-DTQ.<iRA5&P6I+V>l029n@+KuL`&Z5oJAR.mo</LL6,L=+nf(>trM8&op*ge5uv$p@xaY-F9/e$vTFaI\"\n    \"K.Guu#D(v#08[0#E,>>#Gu$s$ikkj1tiYX$JUP8/JIBT%HqB:%`P&J35<6s(tJTJ'`ZLK(R#%ouVXUg(g<YVdP*&@#H'CY$ehLc%^<crdrY$lJ`DJ#,oYKNCVx8b**r8h(`6'6&cq,e#\"\n    \"U$5?@w8]0#?s$^&DrU%6:H7g)B?\\?6Sp]fF4MnT1;4[pZ-<)]L(jAqB#:cPW-Z-V'8:3mx43j@+0rxppA[`$6MCe;t-++ZcMM%PS7M6D^#&#UnL4de`*,?UW-v,eX:f]=A'G#UnL/f-2M\"\n    \"_rb[;epPiDpc;w$jeL7#0UG+#[1LS-3Kqh$5M0+*'K+P(EG3SC&Y7C#t1As?1]Nj1%c7C#buQh,FF0T%wef(#[eX@$pxJ+*,&qv-u:gF4DS//LK1GE/0K67C)oT&$pdpQ&H,qc5h&n<%\"\n    \"XaUK(Yp-d)UA*mNN2)X-.GR['U5ha5odhQ&rNJJ1$->>>'H=2'w=qA#x[N31wWD[%bdURu$Tb&TGZ29/bR51<Q'eW&tm57&[6'C6iM)K(ii%9&@XB`&jt,:&J%2Z#v]2bNvp;YO]=[dB\"\n    \"bfqpL1V;;$clNd2C_R%#vom(#Z=tM(mNv)4i@+iE)JEs%d,#<--Ps,YB'`F*FI)v#P*[gu8>x_uc((,)&n)9'Xh%[#PIwI/N#U^ulv`xF'vZCuG@l(5cqTs/+rr?#+F+3L[bfr/;.C;-\"\n    \"_B:I$2J3rLr#eFuL0k&5Lngr/T%sQ0;pgI_QO:cDx2MfLY$@##RN&I$S6[0#[j9'#+->>#q(#b[A_Xg;PH0_,HB6l1WE/[#;-rhL3U_F*WC[x6tU>c4NI.[#Dt/W-,a5F%+24Q'>%NT/\"\n    \"<F<a47R[LM#]R_#Wnjj0_gp_,qruC)Fj,l3)wJ.3c<,C9,njRN&?K<&9gh?'n>-tLH8lp8t+[$6V-x*+a3M97j?O=AJZ#=7:$[(+#Z5&6M>f`Q8)ljQoT9@M<bm-3Fc]@-i*8tJr0$I<\"\n    \"G*#O<TRw2TcdkvLqI[RCXQNL;qL6D4Ng^r.N4-c*9E<e39w$l1NC^c3.hkG41vOS;pJ0$CnN`v7B;`Y#ox6cVe%mxkrGU`30C5V^Q'gr%pc@A4gEW@,8&B.*O=)?#?]d8/V()T11GBx?\"\n    \"O%G>%>+-BtEo5n&NVS.&wN_v%V?XX$Wepq%q08C&d(u<Mi#1mA[W,n&pKclAEEUh#L^=_/8@:-MA)34'p?cV-t`X0M2klgLTii$[(n#=2U(S/Lm2%&+Xn$##T*gm076[s?HkA,3w&WZ$\"\n    \",39Z-bGUl)_*cf(EfwE@FRJ$le6ZB#]9mr%:;cZ#'l^&4)IT>#mZ'O#^2pWA%$pjL;B`W'$U+naeODZuXR;Q'N+YwLH#xv&%^DV#C),njZJ#0h:.NMQYnVR;99RmQoBMB#th)?#iL0+*\"\n    \"u6@x%Uq2?^>h6=M(6nr%X)/BO0W<..^sFgLxjbk1[>7h(8YN-)O`alAe[6NSV#eQ%-e8e$UNc##1h7-#Bn[p7_2V9/#RU&$)CFA#0J8Q_Y9^:/@D,c4QAp.*;6*jL](FN.J29f3hicD4\"\n    \"vT*COR7NT/iCS_##YB2BH_Q>oX8-?$RI?/u&h.a&/Xhw8*o4*G`'hE5^1LM9m<0@SYTF+5D,BR;xjq69ePC;$7-GND7%3ZuHB)'I@/2.j-RZd3vWvMO?KLTKB-Qs'&p(^)0`:+G0eG5C\"\n    \"amT&-QJ-v6i8db?v8/'5vJcB,I;BO;sdG-2a^m8&77uR0j0D)HjU8Gi4K2,&I)###E?MW&5>NR:@O_s-&on8%mCY;-_,hf1IUFb3+g^I*stC.3wkh8.<`4I)QE5fEn+u3+pdv;^1-;hL\"\n    \"ga[eMkrZ=.+gB.*R?s;6GDP@tTGS@t:9HE++rt<6h.t3;U<:J`^mt3-P[wm/HD%7&Fs5dj-meq.`E#SVjxUdG<EsV7-p:[uQFjUl4$)Ii%l;A+8$^V.6wfn(<?3@Sc>`rQCqaN087@5/\"\n    \"x9%;Qo(3UMUKQr)/c:+G4j(j9%nm$$K>W]+H=$##FF3]-oatW8+t@X-/tZ(HjAGA#8gC1.8%:hLgK'/L$v+>#`w6Z@7X/E$AOr.LZ2-T.[*Gb@tk[U.S0P<LxhG<-<gLE3$DP##]?l(5\"\n    \"u6?:uu/ae$Ux#v#H:Y'#Zu^##G&w%+,DCYG9D0Z-rYrj;w@)[GKUVBu]P.[u>>F;TWpvP29E&MkPE0/1.eoeEg*#TBXb:1pXk/Yp>&xh%ai4T7/c68%T.lr-WNT`31EQJ(U@ZV-,39Z-\"\n    \"&'-/(fpp^-$'=7%%NM,3ksNl<C?v-t]2k4SI/q(E8ZTDl9CIb@BhsPM=f8/LAL/LVgoHKu&<oDSGlv[b[[rPM<1^xkd@$##%&>uuYmS*%P2h'#g,>>#Unn8%h1r58Qv],3RTf0:n%,d3\"\n    \"3]up7>f%RNofv/1CM&/L$r`h3^:=F5Np3_$*lK#$r/(V%FnP-)fe0##)(f`aCLI5C_ej$4H_P%$98.b6;Et7/n(b1B#YkA#*BdW-4@i$0c*(,)-BNJMb#sr$3QEv$?5Q0)aX18.DqCP8\"\n    \"upN=Q+`cA#*4@m%:39Z-6W*Z$4.a<-/Y=b*JhM/2DdCO'[_=h(,2Fo7&PZxkTDPr)l'f<$n)iXQ(dL#$Gqs^%I.d#&$u]+M5eGPMi;DG)uwcZ$T6###YwQAIl/_5#^[*9#HsM<#47r?#\"\n    \"r>-C#5kZl$@4vr-WZwms3W'njr=q_O@<$Z$PmN:IPrbA#J59;2F.VQ7]EOxp#2tM($rPaP`b][>;xkA#;J?:rX7-##7(cxu1xB#$*C#G.T1)^#)W2`]p__jtXJ`QjJtv8'_+-5/SZDA+\"\n    \"9aCY$V4l%lWh.<-l%]a*>)d&OtmF%T[XR?-<:^@RrXSRR$^]=#?khp$BeP9MFKG,MVQ02'/WLV.bNB:#H#$BGKldRBdPl>[i&#A#`id8.D.Y)4GV;h)DO1x5u'7]6GD]eMGxvfXC3peE\"\n    \"Y,p,3+I@X---#Sj]WQ6'Ep+6893r8KtL6>#n1Po7.%7>#w4pGME0l@&;KKpTCCPS7El@`apkPS7I<&KWq87c,?d(K$$r.'5J<K`tOoP-)]%R`a,6g;-q6:h$E*-:)UHeM1#73<-[h=41\"\n    \")[/'#(&>uuE>G^$Yde.%:XUiB[bsT.?7%s$?k,L%ps7f3OU5GMt=Rv$.ia>H)g?#6/bc1%dYDD3,JOae_xX,'6dfF4'$fF4MPsD#b[.O97uv_#e,97;N8oReQ3C_'MWJZ#h%3=(:uJO'\"\n    \":$baa2vBf'CFVT.eH@E+$RYO%hEt7/;fk.)Ww-H+^X(>$sxTh5rB(/L-oH8%Pwc>u'`V&.xY?>Qc'Z%.'19+M=Mw$A[u19/uC/GVMXIq;KfOS7tDI&#Vw=g1S6[0#nd0'#>Ja)#G,FcM\"\n    \"R0@+;Y/.Z$gZCS-uK-a$JRhV@7X/E$AJW[VE34<-PO`X-(t?)fBQ`*G7rJfL4nL5/YasH$]W5lLh,h2'Oj'B#Kn]20i;oO(Bm1T/e,5L#0v4c4TQ4L#rxgI*JXh)3m&B.*jAqB#tu(Y$\"\n    \"[,U:%0nlXl9?Cl7^GcH+3-g[u0v>qaDw72LE:tH-ZtQ[V(JV2MXT_E#k58V#N0jA+1x%B-+C-_u9;Bq%q+N3l,r&W%1*1V%[L1&lh`siLVC/cV6uA>.(/5##T1^&=D3C/LAdZ`*5nOJ(\"\n    \"*A0+*8%eX-*&Vv-b5:R/)SE]-T[I[#Yx$,;.i_jtDJF9Vg[dA#=bR`a[w'/LOS9>#8FQo7G9>RlDB7Z7ZOcO-1Ji-?wa]*%T-f8.&sgo.?D)<-p[_m8N)>)4vVC#6(1^k$9mYT%b&B.*\"\n    \"iH@E+8R(^u>bU_&+Z__&T+AhXj(J4$jjm8/>K>.8J0f%u3FUB#=@oU+-;Zf_hivg:tvn_SRY#aNs76PN*0P-(_XT]u'iEVMo0,A#xF,-M?\\?qg-t36kOSMXV2d-0DPBj6##td1($weH(#\"\n    \"apB'#(18xG%iv;%pp<8RV-RM9.7CB+e=4:&.]m&M:$Q:&OO-K#xMrbRx0eS+jHu$0%X'+.3h+SINw3F70TdERjXK&#fx`m/27Yd3w0`.3cfb#C6+#V)S/iERl_/)OL.8REE]m&M0;sX-\"\n    \"f_*Ob[<qT`8P1IQW*1I$9v6)OBjgO0%/5##_;#/$MsTx72Z;s%Sxvs-flSb*kWXHM0g]rm[Sms&#16TQt+:6&s7drH9TdERI)###@?+_S)MD_SdFd;-h$c<%Q<?tL'=&_SgPu;-tA<4>\"\n    \"4EY&T9cb4%W:`W-^LM2rkv96&_D>E8*(p6*nu(T.hIcB$;^BK-^cg,.0UD78QE_^#?t'SI^i:X16-kW-TW.UD3_Wn89n<l=*pk58wlO8p8N`x.q']rmQ'LkXfa2(XXC1ga$hn%F/7a=-\"\n    \"quAV-Fn,D-[LYx7C0M#$aS2R)t/Ks-M6Ad;7Za/2<Wd`*D/K3B0ZpJ)&XXc%f?uD#_RuwRtTM-*Ja14'SeO-)4]'T7x^YBAe45S---g[u.#:?-eh'M8(Zx#%[4_d#<LHh,c=d#u[A=%$\"\n    \"pKYI85O,`6AY29/-6rf<nBeXZb%_>$W]V/17Ufi'mQEM0Ue$##B[q@/dZ'u$$dHtH@)>)4xNqA#-hUX%c6re30S#K)&8l<MC5pfLd#+?85G74'IqUH-DE3'/2^*FAbLKwKsvh0(IMn0(\"\n    \"pY)?88C#hLX=C[-937&%k^E$u721'5DDnvAd.$##k[7B0-JE/LA^?D*s,idk^Y^s7O:DC]Gm5W-O2'Lu@S'p7n0f%u?`F#$R_bjC-RZd3ZsmfL>o7jL#nxw#1CY,'FI4_JNYUV$Dn_d-\"\n    \"BdPp2Z<VH-v4gr-_<nw%V]B.*g^/:8o?(*#BRDZuVi*.)egJe$gphHV:xDO#'ZAA(1cr5M6wR3qVv3J-](D]0&hX>-KefL;+%6,MJ@[^&tj?D*CD4;-a@:[,.XtD#^`9a*SY.<-9MMHe\"\n    \"YFJGV%fd@&5i7$'O^`m$OJE/L2:CP8(n4t-Dbhf</.7m0x&Qll'S)%G,=,K-&x`xFCQ:n<-^%r`b/r7/d^Y/EPTa&lhd2/LJF1^#G1_h2Q@K`a%(Y4=SbuN+k4TF-7:ot1B+G&#2eEs-\"\n    \"`0v]ObD/[#3JZW-TP:bc;r[e%qx%L--Cr:QcXKl<;8rl-U^`p*_Q1Ru(La>M5TKl<`>rZ^ZSl##j3l#%T6###=4i$#1avw$EvbxFP1T;.^u;#G@m*VLg5(u$lo>d31MvwPw'hD4K)'J3\"\n    \";_h4f$XhL;nB`V6p$v3;Fh%VMOC->u[C.lLMKC*uKY+CAPF$/qD6.Cuq2k3GdVbfL:cb5M:itPMvvi3MSXfRnNDJ/;KP0c$Tp%;M-Ns3;+uSh5EN$`WvP@>Qt@B&GSOFL5+U/kkQnwjk\"\n    \"VlFZ$1TXgL:wP^$l+=a*^[iHDJ'A='fo8j%]fUV$f._'#;e*x#A>*T@o[CE4M29f3<sgNC#TMj9GVZ@-S:d##lIGn&U/Mk'b7_8.$_o=T(B(M/jY,>#Ki5##r:N&lr3:74k?fkuJHrD+\"\n    \"aVrk'Dn?m8+=GhH/D0p&dpo7/U':I$46,xulqJ4NqSLs-+wIfLxrJ%#/$loL:IWO'vR7C#tS))3()7`&hO]:/v?]s$J5h*%0jWI)+DWD#TGE,)P[e<$Eo3@$?;f>%Oe_F*&>Ej0jpB:%\"\n    \"*fX3+atN,+#`0^#WD]T%qjG+I0aLBZOt:wH8_&'RLM,S=4qr^7D3.HNl5Gd@$xnROv]?v6g%peEjCD8WJNRkWf/:cN18B+>8=uFP4&xqJeWiR&e@4fIxaER1cXa0;*SmPfD%-G6id_,)\"\n    \"01G$8R#*EVS/trC`lv>-I;qEHZ<Kb8oO;H*OR$##^8,d$TekD#69g;-BJvt$F$_30?]J,3x/mx4f,0uZHM?\\?$pvh4L-g-iC6Qu%l3UiX-.g5C/ta]e$G%F#+#5i<-rsZF7%)E/L[bHP/\"\n    \"iH%##Gi:Z-Si(?#0SEF39G>c4K%MZ-hMYAO#*pr6D?B:%*X@G;^b7_S]NCD3CcK+*P&hbt,Y$K+DZq'4AlXW@vXgj(1(0,MeFkJ--n8g16CW?Q94s^uSwu`8ToQj*2>>Z5:u@na.@1l'\"\n    \"&?Lm0D*[p*LYU$-ZGgn]V`&JNtlTP#''BKW0jY4S)QIb@bnJ;/p/pPV&g4/MZWqP8)7ZK)dhLS.BXGS7c68R'>%NT/BP,G4p&PA#5aUv617LP86Is@$0Zc8/kIA(#.1H;-bC:[,/XtD#\"\n    \")1m=&MlP%/27J//w?d(+PBaFNuF:V%GET[u.,97;^^`fL)+@20,#I*ZPwSLpjS/F%=I#2p.])puntuP&;BJ/JHVGsLUqU905#-k<?v_-2dLg'8VYS/;/%=O4],Z[9x$0T9=<cSjlni?#\"\n    \"oL<:%[M1a4fxk/a#tUO.PKZL2(+r/2wJ-V%^VW]u_Q71/Yq-4(]$Ith0kk,2vZQp-mKBWjkE(,)jNai0nv2GD0NuD4@V)u7S6Y3L7DjILNgAE+j<j[us+mi@-XkA#ch?O-xBSf.YasH$\"\n    \"*9a'%FdY.+SN4R%Fah/1%;18.@M[v$#q,/(o=hH11%FO'/6>0Lh_ub'r;:B=pTbA#,m.a3C+cIh(LiojJc_puOZ<3h'YxT#s-`@-w0'C-Z24n-OX%+%&i8V?M1S<LOH_xX=#hQaG^Lkb\"\n    \"(`RP&/,@-dorju5i=M]=C`0DEt+j+MRrd+V%d/P]kvBh)04vr-&wA%6n;pFOUO2EOiSic)TJ=/MYs:P-8>1dNhXafNC>jZR3-RAOX?vJ(;vB)4q`l/)bl?b<q21B#$)A9(K.R2LQl8hL\"\n    \"8-kN04l($u<&]w#poB%Owog)Ot9VENY.->#m,eA#7T<h>J;<U)KaHILUrp-4t9X1;,+-gLf,kxFO%w1q&;+AuK$`_&5c]u(BR5+%94LO+J$]2('<_D0?8aH(Oi./L'0x-$2;F#$$rB/;\"\n    \"KAnG2Ta]*%j8[0#dvK'#%->>#H(]i$HDn;%%jE.3dBXA#JI]C#:wT30+gB.*TdB:%556X1RWgf1o(r>$XQ%U/oUFb3$jVD3Z3rhLc>ri435-J*)[aDYMwY5Cjvk.nomn7Bgii(,R-nit\"\n    \"85li(<19h(ofi0EWKZL.Q]FhSt8GV7%pdlC1%%t'v*r<-J@9GPD+lLbhpA:Jtalv,N*(Po_NuD-_d8Kus#Iq.&;O**JX:^5LB(O'Y'f<$/IA>.`WCQ/nJ)Q/^dF;H>$+^,02+v%fMU^#\"\n    \"Vqke)EGlv6?nfx&_u<I))GY###l>Z$YERKut3@M9@&'##g&p8%[8/IM4b<30x_NT/JETv-CR_<h4Y9+*'ti0,_f)T/P`u/*AaZ$$sM,/f0q8Bi<]^2S2vD#5Nx`h1d_f21(Yb.)i#R7)\"\n    \"a]NXI1K&Y1,7_UZw'-Y%..gba^kD*BM$Zi%qLreuaMhV1l3rv#eZg:%KFI<$Cu2r5$^UG`PV$d`vV=c0G[x5:&>6##*R;w$#eH(#[Qk&#P`NH&nV.)*uf[>%.ARY><mQ>6:$pt-VLAh;\"\n    \"[=46']bO-)&@)P2(`BB+%r+B.IEw68LwH#QF2<Jq/,)B5OA2<%@]2<-cnhd-es/I$knSM'-Wgf1EUpr6c@^Y,+L<i-5S_7LpNaZ#L95J$<3e8'UWFVH)l0^#'@)l-CLN4`Xh[^&qW'>$\"\n    \"cv_*MDt+=$Ww&Q&%J4Aut7cR-BDKc$ZfUV$ZN7%#`,>>#Ut(0ap1,c42nL+*Hc$s$d#MG)>j2EGA,Xl(KkRP/af-g)Mm5-*/]A6'R2l-;A66D,;Qg:H]Kg2'm7V(,K?'u$mTsi0qF+$W\"\n    \"S9`B#&cGP#l:sN(K+DE%K,8L(YMLuG'-'[ukxxAKKZaK(G6+A#E9kK<7)_`/_Z`=,ksOfLQbQuu&tK/%;&q:#-WajLBq.C#h'cJ(jOdP/V`&+*/hYt%KGt1)cx=c4pp%J3/_XX$>M*)W\"\n    \"lPlIU_Sg06U`8s&YHa4SV2^F*4J4S7?+i*%2DvX$-n+K-ZcS(sRd%&,h-Z(sRoTP8Ct5<6KXBr6OOciBEaZ_uCBqW-./I/pwclA#FD[E-VO,F#<=D^u9r=^4pg2C#LV.JL[xT##9f###\"\n    \"65;-%^TAX-UG@A4ij[3O&vPA#vcmILljb5&i47%b#mig(IR/2'pi`k'#;HntMqiV$I`XS7GIK9&k&m,)ZI$##JL^,2Uc^Y#a,mx4ESXV-`oXV-29sPAl'tY--ouPA,5%+4u3YD#4tFA#\"\n    \"9)b.3tfrk's%%T.NePFuKH5s-XQaH?)?o%uFO+,'H(=1sZTtp%i)Kf'diIfLv?b'MT8>E?'&L#$7qpO&O@sp%B14,sc5IhLDLH##@>r5/9(V$#,pj-=+$qj(PDRv$st<4:F47b4FrCZ#\"\n    \"E35N'a:^Y,Y6qT`=M>c4m[d)%RuB<%5C[x6I'G=(K7:&55d(i#.*bZM(sip3w-U.9U*t71.1k3Gf]6+%ri6h4WhtT/<(d<-lr6]-kL)+%kF`e$DOv[?GCW+L0s'w6J.(Y?3Y_.G)DMX-\"\n    \"D_/`&uixB+<<Kr.`r21NY4$##iP^[3Zu^##K8<A+57co7?GOcDr%j+MmLR#G82v,*t.4I)uVLh$_AL7/v5Cp.7%x[->=bFdUd`a4^X4=7o19f3C9o.*R_[@#vQYsI)5dK)iRm5/Q@u)4\"\n    \"p<oY-&kMk+jpeC8)@G+@So$s$j<OIHe$l2vFQ5n&A(;?#Q8v7&Pqq$,//K;-fqJ:&Wn2Z#-i2]ILgpO]>djW#hWBf+Crx[u]BHg)rU]FuDgF.qV8GB,0.lA#BRrt-W=IlMpWx(<Sc0PO\"\n    \"&b2+r)s<B#q5WP&Y[h%/-A5>#2IfBJ$$#+%Hr[1KA?l%l])ds-xWJ%RrJ?D<mHsZuIra]+w#sp/Ca7kpRB7o[AYep(-aEfMGH$ip>IH*R@DaSM'wR4]fb5F7&`#AOsZ94P2sJfLShQuu\"\n    \"%Auu#p3###o7E)#QH(l'lsUO'rvi^O&`Zx6n7u*c2Ej'%EkVl(A,m]#Xg_1(l;[IM7l8;62)X61-.@lL;F>e)b8:/3*?]p0XC0h(CHZC''`DO#t)fwLl'WFNDO`d*W?e:AwBr+*dQ-M(\"\n    \"RGDL1HREa+LGqW7ot`8(&>^Z,$>ks6V2lE[XZt2Lr`WY,WGtR8]?e#6%^Tv-dZ%N%LA*F3o#H>>h:ie35IL,370fB/VdDA+uv3V7e`c8.:Et7/EaSq)2Voq)wdJe$O@fV%XV[f%-T`I/\"\n    \"'*=@MH0(Z$S/P:v7,Cc`c-ki'B+$##6'0X-1Mpe=u:.$$fUUD.X&FE+L#@^,@^s/M0GMB#*F7E+N%Vr.Sm^CM(Q>s-Z++cMQ8,,MLFZY#xbLP/=OdDE=0Wf:@hq=.KmLT/^CI8%Z+YV-\"\n    \"LK#x#_ZnG*Cnfc2#UCa#*Q_#$n$eX-/W8f3J%rJWWgDE4KjE.3vW1T%loX%$PUaq*2JY>#5:<5&wC1uuWVN9OqcKi#Fi:v#)p=%P[C$<_0KZVu^s#a3N6th3>t-l1vuML+t%>LF+D*C?\"\n    \"=e>SnD5Ai0BCR8%Z%gb*?b?8.mWYLmc8hm&GS3?mk:8tuucNFfW'@U7>aFm1/(_g2x'6V@t7p>IXpm)6;:t]-OSRBM$C6>#TonfL@ffM:uS+Z$hGS#$(9rk.gCLV$ca2.0,&0lN%H=q:\"\n    \"sshk.j#>M1`E$1/LW^a5@RnTiNjS=uYLkGM+>uu#?hH9i$.ZV-I69u$T1h8._%NT/cq4D#5IL,3i9wK#qp+Yu40s-(p:aIL,u$>#q/3hL).gfL).gfL3gxK#'M&I$7Lt*,vLe60DM#<-\"\n    \"Efo87$),##[6M4%T6###7->>#-<Tv-C0Tv-j#U:%p26N'Mhc8/592<LnMl]#tL*N0-K?C#oEQ)4K9JG;0Fl)4hD.&4ei`u$b_W-*KG>c4OCI8%+'r-MmcYx6K]B.*R4cM<]wNq8-:fA#\"\n    \";9.mKKm=)>TC3dE^N3g,e7at.ssq)&`@`?#HM+v,Ag<aAIACkL)V`J>2u`'/+*uY7A<aV$eHa:.w3Q@5xSeE=2N89=B>@T.1;]a/='cJ(ljpu.],o90$<pJ=_@HC5aFn<.CS(Z#+PC;$\"\n    \"s?w.N=nx+4uS6i4%/5##RN&I$T6###(WH(#MYWI)a6eX-^cnb&VS)'#wHeF44tFA#3K/,N#mQJ(.NP8/)$fF43Y8/L,2SU#4Y29/?qP9MV[-##QECL/01A8%IlC8%4hQ$v-r9%tPVbS%\"\n    \"N6Z5L'[Mt*r_@a$:Ls@#TK-73-Rgmu42cJ_0@UB#c#4GM#7hh#xOO&#xd^w1?&^##rLBP8oZ%##/AGdN2s;?#(tb8.P^D.3NB[oa&O]s$_%6NFoVYA#tG:B#cXDH3o(dY#j5T3OfM4eu\"\n    \"3l_k42ajjEL@ZMQ_$HNFP;v7&8M@<$Xmj/1.krRRqER0XAmZ6DXdsb0x-4]u'j*U`P55.N^kG%P-E*n8EKV'8#3&C8r@V'8vj7vHC4r*%c`UV$THY##F,>>#G+'C4`(KL(xXxfLTpkj1\"\n    \";UL*[s&B.*Q$Qo7P>@#bsMZIHH<Rn&;2W'4X=7xBf_ip$PiJa#o_IG7/EOS[w%)GYjt)S:P=Rs$5ftH=#bNl>$uiJ:9d?(#Zu^##9-(,)8eZi9[-wX-ieUB%&(1+*s<RF4xv_0*Z,Xf-\"\n    \"@6'to<h*30up21L$gQILe%B.#eT.)EqWC1L]@e?$Z9D;-dDDO'6e[e$-Bs,<JefL;<-E1L#DC^#Lce+MIGwxkw<7G;CsPW-Z'FXAKhXj1:H7g)qUS4'+Fk=.TWs'%YP[]4g?m@Hk5(<-\"\n    \"aSfF4>Q&J3/Ux[#N'^:/'[:AXGRR<$q^HW&KhM]FRlNr$.QrvB6QWu94hlJ(*saE*XgU,)>]*.5(Y+CAoeBR'HsH4$Tcq@-J'HZ%C)9duYv39%CIxf(]pWU[9Q<Y+7Ncx#voYl,G_ql:\"\n    \"wMv;%.Pe7&kSv89#Vd98CNV^-bnR[#?MWp%%2PuuBvGv$6%-tL+nM*OFxMG)9Fn8%87@W$HXX/2?8t1)9@g,M[1Xc4&rK,3L1O054HNf<1EoD]R]i[#cgxE%.xTT74-)cuO&89$+rBT7\"\n    \"+?+M&fqb#B0Zvx=K;nH),usj$'us.LfQ*a]XKR(NxW2S$719h(RG*&+nJBT7w@s.LeSL[G'_;;)VIgA#vOX&#%an'HSe)v#`X4V/TP6F%GPD_&L3Z9M7'PA#IsTku]5D$,BS,feK_kou\"\n    \"nP1a3#_+fCwhiS0$>_r$jW4A-6:Y'$3h1p.[wtR:[0Lh>[E*Ma#gG&#ar+G43.<?#UC,wpwh)?#UHf@#moHY>ZZs%$=x-.)$fID3npt6)NgVu5gb8YcH3v(N4;#hL_sW1)V.?_/x:Z$0\"\n    \")E.=1uDBq>O*exKl$?T/&@Gm'JR?s%>`<#-T(5^#hN4oMJtaF.$NM4fTLP#$Pk(tLm'rH-dPViLV:x/M@%jH-*Ja+MO6NFMT%du%U4c>$WJ$^5+u&jCmkpHm0Ys)#?+lo7,t^<LH&HX1\"\n    \"#LhA#c:;n8CnDw$S6[0#W9F&#^9.TK?[_p7D2s:ML)9kLpe(e$pPt9iFBZ;?Drx4p7A.TK%r=d&TCG&8qk&W7U3GwK9,l$#:,>>#Z$SX-dJ?C#<HhD3]0SX-p^K#$gj7)EAi%;2fw4@c\"\n    \"f3_;*>/g>#7jR1KoL]]$6UYCa=8suYK`fSmo`uhu,/aiBQ&ZQ#Nx53WxD#l$E4l#%<9[0#3,>>#cK:,)(DxfLq_21)HDmA#f$$ruG@9Uu0t420>o%P#=jeI:A9mH/BNC/L41>(s?(#/C\"\n    \"P5SO#a3;Hai3Fm/@oqr$*Mc##rPJG&p1`5/^oq;$8tu&>.x_E4l/^I*hf]Y,O=^'H2IXD#seFd2Ynn8%_]B.*[*'u$IiTt6ud#]>+*Wm/A#ad3Q@O%$T`.<$eQnAIrNb%4i=E&AFXwS%\"\n    \"Xbi?#T4FT%%9>jrvk/c$aq><SeH%b5xF>tR%)Lt'Jt[@#R44=$Y`jN2;22ku9TMZ#l,RlXlWl#&Ub5A5jEV0Ch(j[#leV1L)L8..5p1@S5.j^H(i8=(/ZDT)q#i9(]wr$#[QQ5.*w,tL\"\n    \"^cc&#OdaID)Gn#6j:R(#dT?x.lo8f31m@d)+Z1p/dPZ&ubDg;-UuVu$f4.H+##gI@eg'^#E6rB#%CF8%E_.U+c)S.M,N@%b6S'Z$^umh'Jg:D3Xd3#&umCK%,r0hL&I)s?w+G&##<W8S\"\n    \"/%[XH%N-C#WsapuP,'U#O%8P#]jnn,^+TGhIj/Z.n,rr6>X<^-<c&i5Ci3iK+2S50&5>##*VUV$D,0etqap-<^o>1kL0f6/Zbfr/tD*MMJ=6##=(L#$vY9)OKr5<-(DNfLui_d-t8:TN\"\n    \"1**+lS2sm$8rbA#.qtYCQWD:MQbFwNi5vs-i10p7>s[a+H3%29&LvU75;Mt.Ag:9/[5MG)p&PA#eIN$6]NTu.%H6C#Fi<<%MSZ,*,Uln*xwIU(5U3r1V#:B#=ufI_?cRL(^2'i&o-50L\"\n    \"p7WiK*k6,oWCx^'U#)4'uaJ;g?*f:.Xcxu,%BZa&&Z=7;F]o$.cPj9'Hkb05tnWP&d4nK(5JdN#DUN#D=h86&CKa<%f8[eeU<tp%7]:72_@k1BRD%a+BZ^K'7?Y20VM[L(BfWF3YanRA\"\n    \"Z2w$$j7,Auelb>-uM.L(SZwZ9UGnCu)hYn(4Ogh(/fjILm3bp%&,###I.2pR)=j'&;h=G211RW$P%NQ99xlG*.G+_.U(Ls-oXU).o;U&='u@Z5^T$H)e+6J*q?crd#hO=cR;x(Ea,..)\"\n    \"V@4C42U1<)_H'r(<k?AO(86HEp<c(GIhBB/QgO(/`$%9MSA9'/'nX=c#F>;6D].O4)x[t11`$d3c&N^#I);&/KN+KVpj9'/l.g34v*505Q+M5KlN:LEOUZ##X&p;-5NFF(Sq3XAYbw[-\"\n    \"q.Q##6>aILNgAE+#Ag;-H50v&aUrMM-1;)EW.L#$qx8;-T=me'6ipj%(wMFaRrE@$lAm#ul_[h(--<T'V2.?81R8<-B,wOa2([xk[kap.BhcS7t0F@0s$70u,AgJ&U,Guu#J:;$_0R0#\"\n    \"@,>>#0_PcM):<9/x9%J3E^Tv--80j%Lu'At0q7%)/aXj)5+=HV(GOS7/OAL(;KSm(`MOS7b_E+//heBS6.kaa+'J'/>cs.L$>sIL.9sm.uc+:vYQF$/>qn%#Gs9-mZA*F3tC)?#t(MB#\"\n    \"G%V%6#QBv-_bEN0i%YF'CIjW.+B'%MZS@%bCo6hGw((c':Q>q%D3(,)p0ow:rFa-?ECQ--F%'/LgqtH)/#<p^dW/%#ODD6&aPHN:aatA#6tqJFZaDVZg3D?nNj+ngUvMhLg3ZfC)nmfC\"\n    \"PpF<-;,oJM4oS+M%?%^$L-'x#E#dX&F_#*39.`$#W3=&#S,>>#D@Y)4Ukp+M(:<9/EiXu%pMZ]4^oc;-'5XN((p:&TFoTH#jZiZu-&mN'j=0N(@JO;-7WO=lu#h,,DlRc<>B:GVq?ZB#\"\n    \"R96rA$TxE'^V#Q'hkF41.kH;-#fH=lf;rlAVgH=.Pc?V@$nT['%4js-=^jjLU[am$*vOv,?T$H)6p;+33#K+*+SAW]fqQ##-;>V-9+`w,3Gh2810h^#L7U_+P5598ZJfpAEhw7/jDo.M\"\n    \"avW1)2iLhL10YX$Ls4t7sD]RNMsq%4qkYm85o*B,Ya+X$B7&Q/eoi^#x]DD3_#pM`a)_#$0n<6)IMck,WETMbbqP]-C5rj'I*=x#;jO'YER-n&QZfs71]MS]RY)<-wralA995O04s%WA\"\n    \"JkuE6s*?w#R=BMBI/(LVf12Z#Y;_p&Mn^d2+GY##S-4&#R>-C#GKPJ(kS[XdG#7_#O*>uuN$[guYDTJDahkA#bF6Q'A3=CLGJ,Fu^:cY#ub#V#`DF8N(DOPATpb<-MURb%rP8>,TJ%XL\"\n    \"q*js-Cr%r8m'cv.7o%pIb.@%b5W'[utq@L(KBF$0e+bj&YA.h1q'[#-C)O`+'`Q;.$K>,EKSUg*v.U,.]f5p80<(IR.9uAuDQSh(S@;mLw,PS72R8HRo:RI.4QYA#oio[u]2YCj/fp&#\"\n    \"Eu$s$Qq@n%c:oV7Hi`6EgMWGjXmQ%+11^p7v#1^#ZW,=&8Q7^u'#89$5#[*NG6%5fc[`W-Q3n0#U&lq$Yh7-#v9L+*G*TM'pYY&#n^)2%S385/j[RQ/jqC.3(cK+*G3VB#1jM[$vBo8%\"\n    \"rl(T.t4Iv$':]T%+;:8.AQCD3,1Q872nL+*s0f#$C1i;$w62`+Kw60)D1LI7aj*.)xg3v#1vDd%+?NE#(r=_@@(Vv#u&M4'N>wH)/YfP'HcbC#q;06&_(0^+@F;v#_=n6&I$4]#hVvLK\"\n    \"[*Ct(B=_f)In]2'mK/DVI.d>#3(7W$3](Z#piYC)msL-)WJEO'3'pNgiEqhL8x,-VBlc>#.`Cv#oxB0GgMlZG^D+t&eWJ]&40X.$`hfr/21e8%+,>>#uFPS.SlI/Ln^5'A$BYg$T^=<-\"\n    \"pYqW$g7%s$0ljj1q:Rv$YGdJ;.1T;.g_T,2Rq@.*C^LO'/@9h(YDZZAidcp.IoK__x>eS%XXP3'h>+qAeKII#2j*.)UcNT#/j0*W)n`uPaf,@0G61B'u%W9))Q;h(a&XIK#(TjK:.*p%\"\n    \"rMj8AhCKO'qc%[uoRh05,QNC#qi=>#&7`##0K&##Enn8%$w%<6Ms:9/&_<c4cZJI*DfWF3J29f3Tcjj1v:gF4v>#`%*geD*Q/DP-<,`l-4Vw<(Sr2v$2c#AV-GR@'DO[m<A'vJ([ko/(\"\n    \"YH8>GAPg)=22Kd<7IPN1b^.90@n>$cirHEN=$5JEf&mt$D#4]%Pb@w#]RC&?6[9W(AM^n1v$WrA4j9E+PWk5kc+=h(QgQ,&sc,f*/K3FN<CaP&U3BV%m*v+3E=1f).w@a+Bcq%6G:)%g\"\n    \"l=O-)OT_/%KkU3(7P_tQ@=N5&#3xA,DWTH+`#(;.tLKF*MXAv7wV&0%OPE/LdbYX&haj?#W2.)*]AqB#>OIP/PF,l$;G>c4AsqH%Z3m3+N+es--7UhL@[V-*a]B.*tAHO'clkpYS*=Q'\"\n    \"dHG_b`-hOfc(24'%F8:*Bt9h(752JUEX?;Mx2cS72K(<-N%BwYrBjM0:'l<QH8#muGe[h(mNp_eqi_?'FdOo(D$f:.:`hdM_g)C&QtWo(wfS=u.%[8%Cl'29h&^;.]p*P(C8C)4er?#6\"\n    \"9/gc$ZFP.):=tD#4dT%6.bL+*N%s6h:2:Z-I5l%&n@;Z#K&O-)#qP-)er=;-l'HlhG5LT%kBe@)=oqq.s3]Dag'i_(=ilYums2C/%i,V#GV#<-?C-k%kCFO'Uj.@>d68='5H/6(TerZu\"\n    \"f'ui*2)F`WfArK(TI84'Vg%@>d6JX'M8]E'8/5##wn,Z$6#`1.:cGlL[0^:/Dn@X-leWt$mtc)PerWZ%`IE(&B?e>5',^6E$_US7QaOIuC<fP#O`[h(JNq,)fS<miN_2lIV_Q_#r58,D\"\n    \"R1So7C%AiKm'x^e:.v<-q[Lh.dfr$#CSmc%MMc##[CVS%?-,/(Yu8>,<p&##n0h/)Cl&c3p(E]-aqoU/P:;X-9uE=(lbwP/XAqB#==M8.JRP8/ut%320IXD#TO&30eu+G4S$]I*,Aj>R\"\n    \".oYs->tj`<n<Z;%<BE`#b(r<;EE+;HBufR-u7(G.XRk9<Uo>X(:4S]uJt&/Lit%wWOYXq*JBXsX1w@T&RHE'ge<P;[]st*%-_.a$&$E'OHZrG#aLHa*#d#NBIvRa$6'u6&RC,gF?_H]Q\"\n    \"o7=h(PYli0Q&K;$+Ml>#Q2P<L#;6/11'g$'<,nZZ/VnV7/ZK1Ti$DGD3<FQ'T?kq(qr;[>W9hB#Nb5n&)mYN#.hge$ps1k'rlSI-[_$##&&>uu?&ek$,XH(#sNi,#A?T:%W$5N'gHE:.\"\n    \"b3ng)J&d8/e?.J3&S+F3U6;hLMV#J*J,tI3$=rkLw(2#$7O4@$*M0N(1p,x6/xlW-mSh$'gaU#%&0KqRwf[9%CHquK5TxU0+ec3)W:h43K'k5&l$L:hrdUQ=ZwD=Jd.pp,++MA?`5HT%\"\n    \"NApj27;i_,f+2V.[MOq0Vm@v5D`P$6-now#nh,+,NF)hE^ZY=$s`Sxt1NSi^@KpM#,<SgWp&[_su76S%2f'HuA)KY.P(;Z#*U.v#_=#C+nx4`sZTnG*5DG>#GKN>#S`jE*skZY#sncv$\"\n    \"VxIfLl>T%#KSj**i%^F*0]WF3MBJv&UXH##6^TlS;4T=YPuG;-?Jr$b93dr/JFH##o-'O'Y&R**Jx%ctl#xq.u%0'5b<^.?RAnx4KVR'A>qwX-)#F#$?L3N(#]^b*oV0b*AP;wPkIMG`\"\n    \"ehPp/m&UdO-Ye@d,2Fo7dDDO'#?Q*&<=$?$Dt-.MemN=c#71Au'[:Au4Q-e%<WB9RVWO&#x]s[t1><p@3(35&2.co7um%##27AC#S+x;%Ei(?#x4'W&0A*T%JA*F30B7d)[]@A4fDMx-\"\n    \"(6Bj0<kY)4aI%s$*Af_4vf%&4OKXV.RVw;%mm$B4+T>=$[ZTt&3+R8%vxpN&]3qa*[-8u*#]qT%GcsDuZ>ox&BL*p%-<qTn)qm_u(J,R&H+?bswirC;lo%1;1@q#noK^GDA8#=$g`Ip&\"\n    \"JY1i:5_Og1`WbX$a^[h(4*rw(Dl?d#X6kp%HHxuGO=shpJXiZ#LhZ,$`P:FQ5Lxe#]Y$+QC[61M;=Z)O)P_PSr;EYP^9(p7-/^<rGK4riCC9E#,?*U-Wf<q-.e77jXDKHQcm&w#II_/#\"\n    \"(Dluu$`$s$`7###7;&Q_NJE,#vgcDoZ+Xl'6&=-Vl[I`a+)dX-@U$f=*t7%)iM6['Wk.[#9[_$']F`2Mj[@`a',`$'t%4GM,Ag;--tEU-%cOZ-v29I$,q4*V*)'V-GeH:QkZla*<x$OB\"\n    \"teK/)=I$?$n13'OwQ>V-L.@=-XxP&Pj7im&BP0[gC-<T'f)^njR:p#%v>KYG?(H?$tr=>#OQ?dkE?(*#Hsgo.nGUv-1]WF3eM#WoH3@K)$3Tv-$t`a4fDc8.7@j?##Y+T%k]B.*<_G)4\"\n    \"'$fF469v;%abQP/NQGX$chqf3w_603FtK*S;t$Rp;'n_HB#Ue*&/a0((#3SCF/)(=&N9IQ$0-l,KK0P#FaUg(EPceJLVsq:oY5`>+3DQ/(2L2Fja:U%Qr(<$jb[M*H@>nDOk:,2ef:S[\"\n    \"WpY/(3oF[5NQGuG.p+aNJnQ1Mqdh%OSWp9,k$S/)+@6fVBWPsO$lQ.8fV_>$kc[`t&7kU-_T_o-RSJW&/rJfLTk?##Ta]*%>7[0#Iqn%#c+wQ%0M0+*^rqxnwrrG)lU9+*Mq[s$S6;=.\"\n    \"FkRP/Jc7C#)$fF4&,]]4nPCgCGQ:a#KjE.3pfWI)G$5N'*oJ,3a(-5/MMds.uS*KVCYQ=lNgAE+/#q7/d/ao'wX8L(G1KZ5WkmB85UKXJUGQW.CEbn2`46C+Gw8Q&+i>C+@FS[-OE1,)\"\n    \"Y?gM'EHhc)(O=@MZk5`-4;ia6wn&/LN<AZ5Zcr?-xUI]67Rv=9V.r`+k_H>#;cAJLf[mY#Nsj`-l3BQ0rrgM)G79,3ignc*9FSw-dcVO'3Zu.:Q>Zv$T)bo7u$BE#wG^s$l.J01ei&f)\"\n    \"w#9Z-#o$],]TdP.?f)T/XuVH%`Ulo7CnUE4+V'v5hbK+*(DpV-/kP^$;O]iDq<s4<pL)T%X;[h(P9cj'@`Kn1+()%,Gkjp%`25p8C&T(+Upt:.5H(8UWeZb7G]tm'w1n$$'=h)>pi(^u\"\n    \"VMo48px[v5xFTA?[0rH)9)`p/x6/],.87%-FI:=6q:<t.?4:#?/EpY#:`AJLeLH>#M-fx,'I,*GL:D)5xuH&#'R7p&e>MT%hqfi'fBai0hqAS@]#QiKN`HfUCns@b(7l)4NDn;%_^D.3\"\n    \"L)9f3?UZg)0q3L#E&wJ(O$j8.s^v)4jwNcYapFX$uc+gL`50i)+g^I*:oEX(+k+T.xQ*c4h_IU.$cGg).3`X/L5K+4pdwt-;pCW-]lwU/Jj:9/$-6N'Fp?d)n&PA#Rnu`4%[*G4bov;%\"\n    \"U+fw'O`NF3%I$T/'9',.JG2;?KO1E4Lax9.c^[I-QxVO=rdn8@A4TM(rk(@,_lcDu'Bh0<@/[W/#Ios$vUSM'8P487-&Q<.@NCB-.'P9%0U/m&pXiC,%TXiCPd&+.A5,Yu'%Ma#BC-68\"\n    \"nhF1pp`Y=1ApNI)#n<*OUU@x03pZp.)iO5;78p[%#p7T&OV5g)k4)c+F(0G3<`v3^)(dI)x4KP8jHP'A<F/=>T7g2BBjM4(7<+/.dY+g9$vD]X#iDrQO:,2(lBX]u?W#j'vMu_F)hZO0\"\n    \"`K_1p,Y3h)dnRP'DMD9/6KV-6Q##',t_6K3`,wd)[Va4UZA8q3)JAp=I&@j'I$?51-MY5>oRN_&k)E'>5Eol/t=nU@Ml#]dvgLD,rQV]5Q_'c+'&1fu:KA[#K+`ZuQKQ_+V<#B=EHU'#\"\n    \".D###Hhtrdlx&58#iZp.7$S-#*`W1#oD]5#MYWI)KeUN(ont[$pM8f38QA+4H0nO(O]f;S:@>L%n02N(*lXF3=_Tu.AEC:%V,+Z6l(9f3SM.U%ln+D#w>pA,l@[C#M@i?#xVlS/Jj:9/\"\n    \"W=[x6]0x@-qSID*quD%$9Kt6/vNHH3PfCE%VekD#K=M-QB<0r.wjPU%U_5d/(f^F*MCI%@vCFJEd/2:CLmo`?rQow#<x`m&dX+D#w9&C43<p`?s>4P(0Le@@&G*j1]kPT8sH8A,QA3[.\"\n    \"8)p=usAlc#t9S<?.2B]+'d[;'C+D9.T$YrmtJGjBpxK$J?dit.GosE#aqcp8p9s%,L8E</@:I@@qE)7'5W+v#p2PA#uQ80*VA'o8Z@,<SP?M:dCVsCN0AP;-_Wb4J$tEZ6Uq0I+j*mTu\"\n    \"+HGc4':^E3CC-'?2k7H3#8W_Zohn+4fqrv#C[I99<Xe:?dglf<Ym0u$d8nXp1Xv;%*x4gLqJqM'/R#fq^DqHO-AQ@tBa1oLOFTd<V^i*%sW,E=OuYx6?SeC#`e+g-hrqB#M6YY#JP.JL\"\n    \"U2&)s^hHP/*`$s$s[`8.r@fU/e=7T.BC)?#rb%T%^BqB#N2@A4A3YD#b/9>&L$;mpT7d>u(_#('>;]kp3Rcrd(bPIq4]D6&^.qg0O/=#)gs+S/>bPJCW,]n1p+@`aRxJ+*pi-C#TfV$u\"\n    \"l0gLT/HuK1bKF#$bDKfL5R$m8+==kO5+mKPrX<9/N'*=%_Dic)Y1K+*tEnb41L`t-kk4GM_<5V/;]@A4_;F,'KJB.*g95q)kYQU%upk/cMTu/(hfxw#.;I-`d@>fC>NqG)kP6:%0#K=u\"\n    \"L4dDjSUU+'QOZ>#:;$n&cZ3YuHoY3'R,Ku&nsp^#stSp&sr9`j`^WE(*%*7'R2Puu4L<9%uP8=#Ft7nL+FnM1nXW@$>dp_,`/l]#qSID*_?T:%B4r?#a>Zv$ink/2e1F_$*]7C#Y985/\"\n    \".u587F%sD3$9RS#2X*M_OjAP:FgnP'E<x],r^JR/2/^D#cw6T.l[([,6f=m'>aftuJ94lfx+@W.3CjXQ8CqR'Ap+Y#anFY#G,i;$9Uj5&`NOt$fs=Y79aZdN,L=]?l+tE*E+Vv#De*p%\"\n    \"3u$W$L1V=QK0M-MwKs$#?#Xb$mOUAO9-(,)U]W]+B+$##FbR@#FM[&4H;shLNS9d4N:V?#ehDsu=,'Y$f[e@##5H:R'6J>#vRm@=6rn+)YG:g17=K`*$>ru>g[^7[u@fV6*ET:mGBkUm\"\n    \"B;s'M+N$C#l-0xAC7Q>#`4iUm8^T:mWuZM'[-(fqW$H>,fo_@bFeNG2)5###i305o,O)<%=wfi'__#'#($nO(ElL5/$'g8%6$6GM*-;($5x:?#=*P=$vexhBCqQ#$TD)V?,8+h8),Xe#\"\n    \"v)OU#N7>S.LtU;-d`TUu%)[guDS@KU,ISA+IXhiQUvnJusYUPJXPsd#6-x<VaA1?%L[sY$pv?D*/an+DHOMW6YCl;-Zfv@-.cLs-;va.3HCPQ';@i?#Q&@)*-4#'$vx1#$5q.u6FHuD#\"\n    \"t3hfLKrR_#KkRP/eh+/($<B<-hXH2&;Lq&RnhfumS4v4nk=;A=h7$G4oN/U'q.'K>(:NO)Cxl>#*O)[$HmBI;An[xIUN]Q+qC?c$;-AQ?,6cufFbXGMqZPrd1Iq^#;%sDS4hJ`Wk7hum\"\n    \"fdxD4JNE`WDMYc-,9i`A.@d2ic?W$#h^nlBL7^G3e;@N0PDRv$.cW@$i<Ic8@4UB#h#C)KX'FS[)+-Z$Ls4d&n_h=MaQr.MF1$##)_JT..Yu##J.hw/:shD3BKwb4'eYo&r/Iou(nb:A\"\n    \"6M%A4KpH5&S+1T1G5prQ)DXr#nD@OV$A<d,j?WV$sEE`<x-B;dC^$)*;UCP8udd9DpV:u$ZG@A4Z/QA#qHA8%hk$],EHuD#8q[P/]C.[#bYRD*[Q:a#uLffLhRNT/Lp:9/KY/)*D2QA#\"\n    \"EFVv#C0Iv$VRV=-@Q0S/(e*G4DvR)*x7&aj(Y2WHdE&&,C:@e4upCcB`<X;$>ZZ>J;Ma610S^quUU?X7<EBg4a>[O7i3e]%:D2X.w3u@D+,3]7wf?v$Nnk]4/pc/(ML]`$CTp%uHN*7R\"\n    \"Y3xW$XF-9._nrv#jwJY.'kGR#eChmTslcY#u$@C-?N4S(8EaP(I.]',iJR8L#8mj#:EWs%=nK=%0$a%,tox>,sR$9.]5xLCI+KI2o0BU%][j=.b&[q%u;Qs-jjopX7Ogc3JQSB/-pS?,\"\n    \"OUGu%F%(HZ&<C_,43lg15@vo1m+X)#cqZm%nWn##^d0'#b<M,#8->>#5L]s$G+TC4*oi?#xg;E4eLG.)@4[s$Lq[P/&_*G4n5;,)0cNT/*Lum'f>'t73]CE4i.<9/wUKp7-(X^,kh^F*\"\n    \"e$St1cFRh*=:?j<qGrB#j1To:s^r6E7b5P1o(mZ)Us.nTcBHT8@>dw-QB$n-hpMV&-l2ku?.tW$oM*OUgu9^,)6HK(A2+qutC4?/8txS%ehv>#Pm(4'Dc.v#/A4#-+$ol/j-gT%JP/$1\"\n    \":?XeDk+6]6<N[T@Y*gP)%.YY5^n7W$Xnn8%&V^b*u8Tv-Fk@@unZ.*+Wo9(%S#n+=8ZY6)C#aucr1E]-VF.t-?;__,8)+j.=mxt-Y5+%,qq87/ErL?#1Op['Bm/##O9N-$;7###krgo.\"\n    \"P=@8%:J7&4vRHx6HHuD#<c?X-)M4I)[^*G4OrqL*Cn<bZVr-&YRtVN2Dx?8%kndc;WZ[<-`1AXftdtD#25,^IMVH;-uutx@rhG[$)tl+uoOoc3$AdY##]'6;nD>&#vatO3$?Zv$DX)P(\"\n    \"V$vM((36N'v.NF3s`?v6InAw'iYa(780Id3HPG>#=2Wh%xRS(4%2Ww0jiX<9:E$+8LbP2;_=ID*73g@#gCNM9n[APD7MWkuDK45EB7FG26GlhuF^8xtl&tV$<V@I*9?$)*T1h8.>L75/\"\n    \"`3@6s/@KT%V+8I(1OTF&G.)Zu4#bp%8_KO':QA$lZC03(b?=6&s]i-))KBf'Q7Q^t9C33MIYvu#CdL7#p>eA#Ru)T.BKc8/<wIf0cc@A4KNg@#mCB%O_JA1(iSh5Mbu^iBZM*.)b1:X:\"\n    \"R$%M/iw4b@*dm<(o8R&#$`uS.?8eO$$BD].vkh8.M]sfLFb8uIe>BZ-2Sn`aK>EcRUh]CM2C/b-/=Y3b+UQl=*Eg;-)1w/=&%a..w;VgLDNd)/l^b6&9]5=:6t:CAFOTF&@D<N0E6###\"\n    \",vv(#xW3d;;8^;.FY>W-XV&eZ3dc,*IL?_H7QrhL;rXI)U3B:%3ij-$4.?c4Z2QA#jgtX$<$-SL1=0d>DLM.=nNkGROfAA:Dn$N1U9S?I9qdI<gxchu*m<;7MY?T8mQ'[[);G>#aD6?K\"\n    \"IrtY-1=oT%2KPTm-Gj],xWGZ.8uH:A1kIP$rGt3;aAIR&A9`OEcR[w#3G###'&>uuYg8e$Q6>##`OwP/Z0Wq.hb?X-5:GF%FriOu^`rS%sw$0u$]31uU2V?u&9VJ1#Yl@F%DvRI9O)h#\"\n    \"'X+.u,x4wLxKG,Mq1B/L'&Lq;wMsx+R,Tc;nl7R*<,Bf30d%H)*Y#<-#1Zo$(_'T.SZ'u$c@K^$Ut;8.vkh8.Y6mS/Hl;P(XAic);M>c43v+G4V0`.3j4-J*o+SfLSZhV%Y)'J3J;U%k\"\n    \"<k[=-ma9O-1LdG*-9a?6-[SA69+5Q1=T?D6?Y#R0.0Sn1*b^VE/OL9L?<Vm&4FwWAQ6u?%D%)?#-oK8/Fpb?64Q7.MeXEnLde7Q6uASr0s:sB#KeK2)K^AX7cwY<-w7*Z5.,@MTb'dCc\"\n    \"arVr4lV[s$^+sQ0lVn8%Ki'TNd%On0M'po%r`oXu$2(?#:nfi'M$A8%^UUS.H?ei9jJ+##V::8.uC,c4C:e5/dG5t4YHj?#=@[s$iG=c4LJaD#PlwU/j=Yd3+6k;-4aZ*MEr7C#N'oP/\"\n    \"Lp:9/*#u/M<>@A4X5V:%WD+G4%Fq6*&vjI)&@&s$`'A>-rJhw-Q`>lL8=Vs-sPqw-Z,jhL3F5gLhIj?#s`[D*F]X$/qa&],lL&:)_K)T/Ha*XCtm6^$s`VO'?I.[#)Js:/YiWI)xKqhL\"\n    \"V@,gLB]@U.K*t?#hO6iM^^o8%9;JC4]Ve]47s$O=M_a3=M^*<%?w6u6h[T8/bM,H3$`[@#t.%h)4+T=%>nt[$G,f>$:uHs-/oCkL'TrhL>#lI)GN_$'df6<.vBhhLC/L+*=.i,3%Ck]#\"\n    \"T@gA#r@rQsbG+jL%BGGMq6pfL5r+G4aY5lLC0K;-HD?L-l:dH.G<'u$7E$^,RE-_SwG6C#hc8T/A-+mL:;n]4B0+qiCPhD4Y>P%MTS5W-c/UHm-.9e?*iqP'?BwTVUZi2D><vs,rLw`&\"\n    \"HNU,)B.8j'Pbiv#q6e;$5(R8%E<lJ(,DlY#)<G>>iu_v#0](?#,U[g:,F:#?@H'$-Ge&q%esP3'nQV)+UQhG)J_Gw5M&[)*2A38&cMD4'i_^+*]1;@#rPYx#('W`+L+wo%KUws$J^1K(\"\n    \"Qxfb*JoG>#r$<Q/@na5&m@^^+LeO`#8d$Z$?(Mv#@TFL:6'e(+fPG>#2[qN(RE/a+JilY#AbE9%IJ2G<YaYO0[A]Y,w19F*(QP>#g0I=-3rq;$)SNj1iiiG)=g[w#=*9N05iI?$:V(v#\"\n    \"=?2XILBwR&&A6hG?HHd)A1mY#[5.l'/'%0<&-pP&7f1v#>LjP&xe%l#HR7W$9i:Z#qB6k(K2EH&Gka9%9Le<$v`_2'G-kp%.AP>#7f_;$B12?#%Kd]4V[I8%<38E+,'ATA2l#@/#.rs-\"\n    \",[85)LA@n9_m8A,[FJU7:d1Y$QCH>#BL<5&bGF[,Pom@-96-3'HInW$MdT#$3<;LLYiE$8>oR$$x7[pI%e?U&,;G>#cE=T%CUHK)ZfR<$&YxX/(4i_.V?0W$X&-h4Dces$fu]^+S6Dj(\"\n    \"hdGN'tBhj(e,67&o:-$6eGxL2A/uY-V4i?#k(o1(SD+I#k7+gL-80M#M9>3'&q1G#FL.W$8VP>#HFnS%2`:v#&h:w()1;`+'@rs-5vlG2Ni6:7e1u^#R+`s1c6)j(l,eG=;((f)<+jv#\"\n    \"vE')3H8B58fKk9%5h-Z,m_rv#mKOq%k]r>5K0;>5GsT$-<k&q%k_'+*;juW.Pg>n&dffB+VM7l'BwXJ(JmCK(n_+gLM,^&$`DM,)5oCZ#QYsE*ATC0(RU7<$8u-W$71R8%3M_G+B(N&-\"\n    \"O8a&+IUOE,sool(j59f)e2t%,(;9p7d-_>$/$hj'66-j'+QTe*2:9U%:R39%j9S0:0U=g1_)b@,w9UG-kejJ+0csS&&I-C+57RW$`N#Cb9oU;$=On8%n%8_4q'A$lH:2?#,DG>#J_rV$\"\n    \"vB3T%Bw82'GnS2'7(7s$7VC;$bW?'+x.fL(Z04=$V6$2(c@5?,LfG>#D)&#,_(H>#&rsP&Rg>R&WR=0(Pias%Odhg('n>_-LeJ2'%J=a*`/vj':[^q%P*fs$Z@7s$ATDW/r86l:w`[1(\"\n    \"`B6L2<^,L4?@lo30HqYJ,pA>,Lt['9*AUoDcaxl2AfmY#4QPA#Kpln&#;FQ's0A9K'C*W-ig.iLLU3S&wqGt&Ygj`+=P###m7bZ%ppN$#kd0'#.Q?(#c*2,#Usgo.w>v;%de2Q/L[=%$\"\n    \"@1vV-iL0+*f*H875ESP/*Lj?#vN[5/;'Xn/N2m;%RT5<.M4M9.2MMT/vKt-*qSID*^dp_,/?n4(<>)c<xU3T@_AbQBnrrB47iaF.Z(/aM?tF]u.cGN#<v7=Ruwps.oY9_IancO-21M`j\"\n    \">TH;0lXheq(>cY#r0fb;Y+?>90B5p'ISpM#$E)3;h7d.)U@hS.7[FB6V`E8&'MK['$U1L5>CBd)N<cr;Z&08RLO2B%>cHo?fAfv8D(`V$b.G+8/Z_T6e^RD;%utI#ncW=)W^m49TQ9[u\"\n    \"7rEQ#mI$E5=4(S0J_.W$5+Is$OOx:dkWo<->Z./&LBY)#-->>#cj>,26P@&40Pr_,m(TF4g48C##F/[#m&l]#q%^F*ig'u$Dfn$$.m@d)^^D.3A>=,MR]XjLX.w8/qC,c4>;gF4x2shL\"\n    \"'t1C$u7XI)/mtoR*Ivl;Lf1&,TvO<Q4(fW.'<4C5:,#w8'a=</=fxxQYPsc<pb;l2$.(,3>@F]:]aEE#=$OwL](G'QK(]qFlT0%'#;=,M$x8E#dD+J452ka*Q)i0(_Unh*j^wU7e-3p1\"\n    \":j/V:sD7v.$>jO'eTHH3i1%@-mxV5M?%HGQZ@b7(V=fV$])FODX)mW-XJq$']####&&>uuaU60%FKb&#Qi8*#<Z*G4fAxiLTk4I)EPsD#s<RF4bSs+M[>kB%iHhx$C$5N'MPmp/?eSM'\"\n    \"Q^v)4cx(o%6'B.*(^'G+_>m-/W<s?uBZ6v$''&],i4$],O3]<$1jXCjT,>B,^(ht-OTx$7IvZ)*;&Q]u3wNT%5[[L:Z$;I=>dU^7pI9s6073Ib=b$K)acR$B)kUl'e3?e6SXpY%`Jqr.\"\n    \"vOoau#pd`(;3a-*IruYuh?Xp%cj$gL9,04EsX6@#d*HtL`_D6&JU7G;:h@%>hobA#(XdF<`)[_#XTMZuv][h(wABf'd-EnOvg4F/(]'O+9aCY$8ulca%3f'/ta]e$-<gi#SpP<-vO,W-\"\n    \"7#,c.+4nERa)###(DP##:.ac2]$%##bkh8.==M8.wI'f)H&lW'?D,c4<]`#$bHQ8/.=UB#5IL,3QU@%#<g6T%h-mx4*sMxlxF26/o@gm1J];gae1cDs/NIG3?6'@#*w?I#Us/F#=`a1B\"\n    \"idj9M=/[.02W6>>qc[t'uP(^ur>,<834j6/`hr?#Cg^:ZwoPB,(HfQE&WFn*:d>U2LY/GMw>5,Mlku&#I+NM-Tnq).#xS8Spgar$wpV?$9TF+5Dlo>88LC_&ck5c#d_weuA7ix0qEc1B\"\n    \"93dr/G+Z=G$?$pf2c6F%.6Biu/8=r.JZ_.GX9dRN'jT*%S6[0#Y?O&#2uor6B.<9/?1[s$ikkj1;@i?#dSPp8ca&&$BC.9(SUfq/H^(V.,3Od*dj)k1f0x<$._bW'tBEciX_0*-'FR&,\"\n    \"]#lu-i;soAV&l%9h%Op@w%>>#3Uruu&:;J:WNT`3.v*Q'Y&l]#e3so.FEuJ(lh)Q/x:Ls-_%Is$bp*P(g.<9/[j:9/Bb^u.+J,G4Wg*G4E+ro.FV'f)g1^F*a&ID*0H%H@U_wchP;/+%\"\n    \"i&O]Fil9%kLIMZu4N@<-i[?%kLCDZuoE%W$I(0-&=C%@#djgo/[u*-&Y0PQ#]*SY-@a71,0Cm&OxX&%7x(0mAaOw6&50-js?vHOAMd10(g*ma$HcBasgE1hL?Q()3HZAp&H9]Y-;V4L,\"\n    \"iYm3'w[C$#%&>uupB3l$b;r$#$sgo.=J-W.qC,c4n?_hLI8E.3w0s;$StP8/B#Cj(0UE6jrd5N'8']u-b-ikL3)$`,M_WZ41kU7e`uh4vPWi)MdBY>#,ER(N/_nUmPB/JcQ-B?1i*u]>\"\n    \"KRsnRP+=$-ON>)MXsUE4'miL6+3K'MI@2[Jw?rNJVTb1UL=NUe'a;204S@XfdF<7R@>fP'isI3%`JE/LI8W]+NO$##K77<.+d%H)kHL,3/p#R8'>h>$_4(-4b-dfCS$J<-mC.q.4Y29/\"\n    \"vsJe$*?<r3u'^:/bV<o72=L#$8UGs-8Js%+EaLT%t@$##%&>uue;G^$&_&*#l####jAqB#l4K+*g:Ls-fIe<$6o0N(Od5,2=$(K15?85/o]d8/u3YD#95h*%T)ZA#9)b.3^nr?#EI]C#\"\n    \"$(x@-FEvTMp);i8,ueh(72bl$r>>TBml_OCp]<k'#9Zc*^^cJ(6`C(McBhG+@P57/q6G2$ex]b3@[p4l+f8EukeB5&pv2j3>YF>g;4,.)g%a/(4<cx#<mBk+7gmN'*iIh(nlTrG@?=R-\"\n    \"7fHiMmPYCjg6j9`5.>>#GpM&uc<eJ:85d$'tfl$e?3M+*95v]#q/l]#Z&?Z$*f@C#j*5N'Xm'u$@4n8%_QB-m#(wY#6#I<7^H9u.c?XA#Y<Le$RT:)3oWoP/-K?C##qVa4IR7lL_d1#$\"\n    \"[ghc)`V1W-PMSq)]$#E#NY8a#VJg.*,VfQ*a&9-<qUbM(g5G>#=l@%$d98N0bTd`*T=`[,[1Wg*[(X.)>u$<$%=F#H%2f%A,:79.m%6J6?t+j'mTcn&S6Y/(.*[4([ELo0w-&[#N?06&\"\n    \">_Et$7NR8';`/(4$h(M)U4DZ#/f$s$]vUg((hGv.I6:m&4u-s$ci=;-0OWv#dueS-Z*G50vkvlLKpE7Mc:a6/d_%W$eMwd)KXUX%eTa:.g7U'+Dkww#*0>W80hjm/YD*s$1]tX$@%mY#\"\n    \">OjP&G=B.,[Q&m2M+[S%30EU:QP7n&gg6)*^HF]#FTuJ('gff3A`us6Gi3s%oPLl0ID`$JB(;v#=GA87B3Kq%*Mc##*hKJ%H>f-#BL7%#t>$(#7H4.#ssgo.YcCW-wLNC&g+TC4q_QP/\"\n    \"sMYx6Z&PA#FOVS.b:ofLAfw]4b$@K)WcX;-V>%&4O>@[',-U:%)m?A4w0`.359+Q'KINq2jDfY,FHVb7T@=<%&7U`$U[0:)5dg<C)IA8%0LTfLleg3*GC^I)wt%l)6&+-=a=,3'g>2K(\"\n    \"#ir4^d4(PEO0^6g^eMH#,S)ku?qlqub-xGVB#_lkqE75/j^Znu[6ZruQN;kORNRV?5r+@$L3Ot$esR'2/:jV$+8J?57P3/>-hSj0^4jd%oWLA7o<&W$=4bD#*kqU/Y@)G+T,Xv6,6;,,\"\n    \"EU7&,[$k7.K;gB+wKTB-W:(_+E?>3'a$'Q&m6e^.g.n#An4j4^E<0^9t'm5R5/s20_G(;M/S-?Ig*YJ#-_i:NM$v]'6MuY#2*X>7hX#R&xRF[5Le,?A,Id?K5ce;7;rb?KM;wZ$3FuGu\"\n    \"3aOi(xk0u]I,Gl(Z&w12,mv6:Sx$HDIZu##S'+&#Q=h8.VntD#%8H>#QUI8%K3<l(`qs9%<X)P(Sk3=$rfU7c?=`1.O=W.UKeZpX,2@&4W-1l]h^]..0gEisB3-r$xX@%uj916iN2;R#\"\n    \"hsKi0FuV*CmR:Y#R0lpu3^w`%F&###M>H5J?@-DE2RSM'1j>,21u68%+dfF4=<Ea4eYm$$i7A^,KOQ1M,C>,M5XHv,iP@l1_wI`,F6#j'UsB:%>2^F*5^NjLG4]T%E66H-P3`tBscP5(\"\n    \"DjlFV;<)D+fdoi0T@]<A2B^f=]MHYN#YU(4L?xk9p;5c>2IwM9C&]`6=9uX$VlJ^+:0&S'3PS-F9:Js$Xt*9%6bfM'@5`YAh_]P/X^o+>x+9L(5c=a*URaGH`'Es<MdD#$som7&aHV@t\"\n    \"(9&*+p>Wb'wmF01o>p42JiSO;u(IO#<*cJ(6FU'HT5o-)[6k>7CVW6Jwt.492r(JPpP=h<pF5V9'.4X$bm*E*F:+&-`gjqK84vi(-Y:v#^e.E*`P`^#llZX$7iGn$/l:$#GF.%#B,>>#\"\n    \"(_Aj04cQ7VbPic)13t-$b<fX-K)'J3;dY=$MnmF5c3>.qn'afh)DC.$#.Z($7-XJ#Mv&AI$+A2'3hDE#j)GuuH12I$[hSW8[L@s:3.]*+$NYc27-CG)T1h8.HQBC)#k[r*7,$Zu^`Y3'\"\n    \"8_>C'W_`?#Zq>n&oEWDYi%n8.BExDtJ9Yt-=R_c*WZ,=-<U.u+c$H#$3UV)NS5koV)M,c4kiE.3#VYV-8d%1(+gnP'SgOA#nZ<J:dE6?$nPDZucpr*/KJqp%Ij&[^a4D<'vsRKZRpaF'\"\n    \"m_=h(wHUv%r7Eu.m'R@)mHrgZ2s9m'YnIs-K7ow>0;7OX4WY0:kFN@$x<1J)9DQd+gFq_(#aCB#U?L@+bN1RuEpop&m,:Z$vjF&u(P]7.`9(,)aeT&#bv'-%p,Wm1n.fa-fS&3%;B3oA\"\n    \"3N1^#RdSf$0Dqa*v^CU%-15##)]$s$g%q:#oid(#A<Bu$;J-W.KJ=l(+ri?#*-:D3e3so.i=h8.;+mV-@G.$$kHuD#_R(f)xw50)<OmG*KFP.)rDLe5K1gBU2q;BgAbT)Rd^raK62n]+\"\n    \"kF82']u&kp2)Cr.;DhS%Umk:8SG+w.4$[(E$Ax+0x#mo@tM3+U*QBB^fdE2M#s:X_'LI3k7ksE%F1,o-YT:0(d6a;Ai'WB%XRS<L)&3)#AwJ,;1>g;.7wv^]%`<9/miE.3g@SfL9-NT/\"\n    \".J+gLm++E*J)Dp.a^D.3Ok(k`eGQZ$xsqInr92B>7d+G.M_V<-iqjiDO8Nc3;b%/3mD=n86o?xjW+P,'Q6eTi$$VFrWd:fj53cx`VBTj*i,cg3w;st4TlBB#p[SE@=nkA#.$>D3-JE/L\"\n    \"hE%##>:M;$BKc8/wb[s$VkJZ6CE(E#I8ss?q6bB,@Jg.*]3B:%x.vb%8Ge(#*g@J2ej5nuNUW_'lJ>s$Z]aE*hh>W-/i8U)&'Lv'vD(SI9STJ`m_fq).qDXaYvw$).)W?8DW10(`rMj9\"\n    \":`em/P`[h(a/'d$He%Y-4`xb%n/r4'$sb$McLvu#46V&#>8@i.$WH(#-jaf/vkh8.pZ'u$-SsxS7H7eMeT]L(Z'YUIAwOvI7C9/L8G.cV<N<T'oU?w^hbi?#5&mW-b9A'&2G1LM`J<iK\"\n    \"6][(#'/###,`a/LO.HP/;7gr6sg%##;V&(1o]d8/GWRl1qL>c4jF@F4s3rI3V?+^,[/l]#M=@8%d7Rb4lY*E*a`MB#t=Us-hLo+M](81$Y_M8.]]B.*^TK>$MQY8/IA1rUY5K-)T[gk;\"\n    \"/w14'FCxQF,hZNL4REW14>Z8(`QR&42pvs8pH-DsAEp(G:`Q=l,pr#ACc(O,hx#@?ca^>$1tXO:dp_7uB/2GVI+S[-hjYJ(hD3&+w:HX7..=x#ab3X.?3Tw#boBo.[MOJ2iBB+igGge*\"\n    \"[XFl7,3Xxk5iGE+jX[2'nldb<;4n0#NQW@tTLr8%^+$v#O'i(EKTEV/xCM;$K`:Z#(TPW.FhMl(Dh5A4nKEJ:O4Fm'0fvb%*XJs$FVU10`)YA#fd]s$U_[Q/mbK+*[cJD*Po'gLCITC4\"\n    \"Ee<b72_=x#F]Mve@a7jiUO*oA=1#]rsB]C&D:8GV-dolB6_wx,U?ss-=0ZZ,Q62;&<=qj(P=i?#t[&X%OTL3CPY'j(RXIw#b74,Mc`h[-6etq2V<D;&9*(@'_s13C12pL93%brZ0n9Jr\"\n    \"JrJ&uLPW;&[Nt<17URA,]Y[b%I/:JDDb3T%+DP>#1N%iLMc]]c?On8%XxRfL5kmc*cbGU2KvRU2@xaJDYOPHME]j8&qx8;-XChl%'S-5/;2ogFrDQJ(?@i?#$d(T/-OWh#/A0+*5HSF4\"\n    \"h*c,2-U%],`S-v$%D+^46_E;$%S]T%Q7g7-bds:4EM2q1Hx^N0;.8$$P5Pc42d@+0Beu/2uT9#,#o^b*$cpb*;(MT.UO?9.0O;E'2x6=lfv2K)w>p59x*.H-XkmYu^>l(5CXq^5MF0H<\"\n    \">uJM+R,DK(@7.W$/l1T.SipV*>vwm-*f0wg$DO,MnTR##T%T*#+n@-#R%(,)a'85/HsUO'1SY>#%IuD#tQP(-lMPA#4hDbNAf`x-rn8Y.NMfD*.m@d)srwD*hl&+*0<Tv-wi&f)STh,)\"\n    \"nRS(#pV*i(?rq;$:2`^#&Je(#vn6lLKfQW.%A+gLu0m,*V6P]F9[2T%ZuJ^+^JdOoG>NO'c-hA;q:bt$<mga<,P0onD`8N0ivRdD'P&MRMnD@&W?b;$N60:%%Ma`uroK;$RYLoD'.Ovf\"\n    \"L7d(uK72l*wG=^4k>S1^xQc=q*Xkr?%fjxNTeCxb6RAxb7A8N05v:FS>PJH#_Xq,)RZ`u?3A(v#h]1Z#m0=5&:[sl&Wei?#7tbmuKtnJN`/EKVP0-0=</X.)xr%p&6-`tgP:;W$q,UA=\"\n    \"gYCpu'C3AXex0_#+t[suNa(H-PNg(/CFWemt*u:M<9CT%>pqr$5:r$#?,>>#.^PW.>;gF4D)2u$TTF=$`^1,)xeNT/x3b=$60GTmOHxmd5ZD$jBw+&49<9,/vZbGIR1<Ue$^]=#Z/3Ou\"\n    \"4k`$XFPR&lPl1s,bK6S7c5^i=T_oi-RM>1%0)S/L5:jl&$H>G2-c:?#m3F4WRHZ)44f*F3;rlS.4tFA#spN+.A`TDN>XF%$(;=CLnbnO&?WxK#QiIfL'SG8.H<g)tpI@#6)S,<-**Tg1\"\n    \"SPrIL`Z29/iS9>#Yn>AO7gAE+9/r7/W22iL#Qq'#%)###W4$$#aq32'Yq$##Sm9u$<`v8/3BR)*K)EG)S(Ls-)Fj?#jCXI)fVwGZ&N_V%MW8f3Bb^u.ak4D#NNg@#..<=$O*tpuJDgQZ\"\n    \"$Axr62jY=$&NibV5P,>uV.qx$.Cl`#[bjaaG7`Z#9jJW&C#6<*v`_pL#o'mAPE^=cQlmmLEF9;6>wCZ#i-nYu?vg4fkI>_.,)*^ud(YgLemj?#4xZQ:R(CTDc<3?#/',YutHa+M0d[5/\"\n    \"JMOV-=+(X3@Dn;%_RZY#q^D.36'mf(^7o]4Gw%?5A7[s$`r8t6pAx8'P_Ho[o9D41J]W4b_,3,@6-^+4GjFV71uZsQNbKr6T4E]b0*@S#JTHk'FaH$Ta6ePReTxN'oiu.NZSRfLfc$##\"\n    \"5f?>lw758.ESXV-eBf[#/1a8.J:8Y.s3^e%wgOA#4?)[K)>M#$]ER-'dN<;jtw-Mf;w@T#`<4/1UPSv^,ES<Lk6p%RDJJv$`+/Mp'I2qu3L9I-=8ND#Q1+ddr)&kk(CA(MJdxJ=7'90Q\"\n    \"gQa$#_EX&#RHLpL>eU:%Ar;9//p^I*F#qE4>?(u$*W8f30w/g:1Px.*,/rv-5-70)AS<+3,87<.D&;9/::n8%.Odv$$`^F*,LZ?$7td)4intD#f*19&</(?-3U)j9+oW`uq'k0(r/uG2\"\n    \"LB3x$<H4w3xK:l:dA?l:`CIQ/CE2_.d*TAdv04,4w2:(k62es].7N.3_/7v$te1ocbO>Z,GA8[8Ht-C#G5Ct61=Xt$<k0x$@jY[.RS9x?'BJ]%WkDl2C;P&%<(Wt.bbi-4K>8d)L0Ps?\"\n    \"8[F=.OO.A,+OroPOxf?5gaDf'TOc=qqx8;-F$u8&0V18.+0v1B[.d;-__+w$<D,G47t(</g8uX$n:7b4nGUv-Ys`a47QCD3%UvkKgUlS/(EF[5AAV3'2Mp7'Jk<X$Kh0[$`kn+2RV6X7\"\n    \")t0lM1ka/i)gC$-gFA%Z;2P>-#ubJ2a>1=$2MKf,,1XA-2)NWY3V`&+93+f*S#P<-j@KoLULSs$jiL5S#o$LMiUn20E%=&-;KBk/WJ+XCb%+[$/p'7%LkhS0D@C'+fp]iZ1w`4'0-8D;\"\n    \"l*]?7-,6&#:8E)#;Qe+4PDRv$dZ'u$TekD#I07IMkqEb3nC)W-Fn=X(2?0W-DHMk+G1$o1tHUMB]b,LHn9'SSXk@(H+rY_+s@k;M;)dD6YxZJ#r8W^'g76J_<[1+Gr'1rm,x9J)060cG\"\n    \"SJg`*,x'/)2p;ZK,u'/)Pu5SJY5PJ#9m1&(N)###NnX/L_2i+MR<?>#Y/j<.]p*P(*A0+*HwaINZ5AW$CsC$^NO1F*$$6P03M4)>l>dG]@t.nL])jR[@l6S#Mdadt^#cFM-^FU%WTVxH\"\n    \"EjiS0g6jrs2KB5&.3N$6M-]`Ed*xTZ1D4kunL9@ttBbW6$T>h0f-cK;XF+6'@%$##qN*F.,m@d)HQ`]Jwx2Ru5.2s@kehR#%CGb7'JWK1R,Qr#o1wcuZC`2MG_0U^kZSS%=d;A+l[erm\"\n    \"1.no%A9GJ(*G#REB[*20WKBD3Lmc)+06;hL/R1N(g#4jL80H)4B=>s.@IVX-?J.`&`hKSu*4qWJd_D&Mmh#v,$Rtko$%iI_vCcPT,eLk+N+.f_@YGH$2)-_#G/fu-PqiuLfjQ'$me3+u\"\n    \"fv,iWA6.bNxN>p3'&>uu@cUV$)[I%#bTr,#VQUV$9F[6%bG+jL7B&],%C[x6ep5V/olOjLfHo8%.0ihL=2%E3LrSfL/5,G43=S_#x<j?#(gm$$x3f--HQCD3WfSD*Gg0@0@Tk++Owem/\"\n    \"1ZYx6GHuD#eCg0%hE.vPwnR]G4YK^$L3k9%e%dGE8q.$?8e=01AuA(4d+bf2fsCK(RhNt$Xs1O'*$';.EO[W$JGir?:2C_,lQEb./NOC?8LUlW;OAF,'Gt:SNAdD+dIwN)]pA&,n_T#g\"\n    \"3CP1g`iYEL#l^4;qMNO'Ac*a,Rh#KLa;*&1JDIY8]$.-3'[3u-kX3t$(U@&,NotV-++CHM$Xg6&2CuI)Hne[#B:@<$=kxi'WBbt$dK+,2Zcc',I<pl/lxVB#@NR-GihQq7^II>#>*vD#\"\n    \"Jhx60dkTkuUX:+HS#$JVh]?KG+D=8&7vpn/Wn?/=P^w+<SKS49b6%-Z9=oD<>_T_,e[ar?F8'##C0^M'(4+qI=E(a4eFsY$-FLF*XQ_&$lH3Q/0d%H)&Ub,26P[]4g<7f3*^B.*2T^@#\"\n    \"-<Tv-Gke5/c`>lLZLuD4l`n]4d<OA#LI)v#Z&e)*abQP/@X^:/)odP/NSsD#Q'UfLUIGB$RPcj,xk78(U?B]I[o&i1i:Xa&Pu-KDJiJsV=K'''vkbw.g`;bSj_to8aI2$@[Ui'H2D72$\"\n    \"M-ao:aFi4`9)5WMuH^oStA3/1pibh)=QffCP;;U8?_i=-eF*nL]p2gV*<k5_Fh/5<m:1Pff=]V7]72$@UxG*G$8?,8M*&q.Qpds.`m2^#K.Yc-wv'LGtZG^,1=/s':FItIi%0.2.0axI\"\n    \"g1'21>3+gMtH[q0O#ovGUR5CH)(sd8%06X:>()O1i_M$J+Sl##)]$s$&6_s-le*;?3<?PAJok(EP.&DW*`$s$Je75/KkRP/=Fn8%jMBNCei_a4aI.[#rEUhL1e*Q/H`:5/%[*G4F=rkL\"\n    \";w9a#lD.H)$x0O+&'PA#wbK#$<iYW-JGg'/F2QA#8w=c4CtoR/`&GX$f0eP/6/5J*;L.@#'q6[B>4vr-$GQ)4d-X^6Z)E.3D=C_#<1Wq.s5Tv-bEVN(F,bv>Q^GX$a&DD3(1J[#3hjI)\"\n    \"@@k<%GxNW8ZG>v,8ihk)^rMn8F@H_%mFmY#ZI,G*[e@<$ZxIT&Hu>e#.))q%FY(Z#_2ux#hY]s&blS2'_pSm&JtMD+Moc>#6]II2n*J[#S_pkt(h+Qu]=^'D'[W'DQ>m+2]Xl[tMQcjL\"\n    \"f=?&>VlBZ%UPA#,?Zu^ZZSNM>+f/9&]V][teu7=%9S(v#MKE*E+QQ_#HLtu5]3Prd>eap%9#I&4:7[XA:S(Z#N,YO^D`M(&SNbP&?wXJ(:Ie8%Ewat$?iUv#i8C^#WFN5&F,wd)@?_]$\"\n    \"tLsu$6@bc2wBk3'X_7w#g^bx#<qoM'RJv.m#DFdnmTQVubWJVQH[c8-gf0v5T?uMt$f-F8?$1*<jbNT%Q$S[#fVUV.Va0u$nUsqdwh)L'a)ZA48x6W$,2s.L.a0o)7Yml&Jg.B4Yd0'#\"\n    \"L%T*#7<x-#xRE1#cji4#?nA=<0@_LNglfF4%FOA#dZ'u$5)&U&<uSfL:s$&4_78xGsBYD43>8*-g&V/)VTdl$')>;-ew,?8T;R204JVS9mRubV7Y<Y$lkbAu94>0L5iMK$30KlS$7>.V\"\n    \"o:;QVWIkILH2.?8<xj9M8]n;8i_>vH&5q(EaZx#%VWcr/TQ[oAPB.nNSch%Oi#?<-xojwYXjEYP/4br/n$,##7&>uule=n*Wsvv-*Me;8l(`Jsece`*OsTp7Q:kM(Y.C#$Zrv98`wX<U\"\n    \"jBFA#K57)a>Tw<28n`Z$uY29/&S4HPvg7%)<19h(kx62LDq#,._WZ`*Lg*EWkPwA-,l>+X&BuC.jH@E+Q9N1&W9CxNvg;+rJN28])1T49aPVs)gG8b*aC)<-Zfav%.PHr)lNu%1nVS(#\"\n    \"%/5##7U*=$_w7-#h^''#>3PJ(ZHpT.al+c4,`aU%H:p$R`-?/CPph?8RWX]uU)8A,u6[V#:RUc<)5u<MJZ@t_4*A%kYB&:8k:t.L-T9F%82<D#%XK+,%<'SmXrT_mE@a8.(PUV$Pg(9.\"\n    \"/i8e$^)V$#tVH(#cbY+#FsUO'BO=j1w-@x6ROr_,?*'u$cMYD4:-<[$+ZWe)k@C8.[GUv-fw]'/K>uDOg6+;.<2B.*Q%a*.AwUB#[H-?\\?fjDH6w8sg;/.@uY?#r3M-6<v5&@vJ#OVg;7\"\n    \"p]LppB*X+;ol3(gW3VA?Nx_p;O+`pJ*p&+>hqs3M%q3m/7N&(H<EVe$<x6Nu-w$jF'rN@I#T9bbX<&s18Aos?9YOrgkDH?<[h@qTMuS,2:_MSD'X]6UN_2o:1(B>#d+9'#Vu^##fOJfL\"\n    \">^o8%(eAj0NaVa4)'L)M@G$_#MQPT1$K$ca;3TJ16vt=Sh[*)$;%o./,+w7/Fd6&4vhB>LFJ=<rqx8;-6_s_6/JE/L-l68%B+$##?eEX$0':2'OZ'u$S(Ls-&SsH?l#fF4c/2T%<J)v#\"\n    \"$v?KuK/Rf_Vj@i9g^j#-k:(88Gfi&-HP`^#<8a-*:Bhj16kRd#O30fuwxx=u>;kP(nDm0(G+#=6r@dl/uS,##3>5>#uo)[K?f+'#V1]/L-hTwKewfi'M,@D*6t@Y-Yu/RN&Jk(NM+q,N\"\n    \"gcBK-g+Zd.Fc*w$=IY)N7[b/MLf2E4:A,Z,xa:hL-@'/L$)wILMHgiuU26c$Y0Q<-ipLE3xv]au:j^O/G2q,+gYOo71chV$OLKZ-C,)B#<SUA4H+,J*3kOm0%==Q0*&^Y5>S]iZ9:4SN\"\n    \")jH2XCj54GZqrQu9Wj^.apBf'AmdfL-U3N0Al2B#:Ut5(G%juL)R_I&>a3U7tYBr_t9%##)&>uu/lUV$Rrun%nVou,x5^f1e<%##:_G)4SBo8%Jm:)3qe+`#Hv-&4hqC.3fmKL)vq0+*\"\n    \"&?8+4&4H)40LR1M4F%U.m]WI))WhV%'HL8.-/w_u-g$s?3FTlS<lF#Ivjddu^VEY#Og2(fLY)]Fuj2D#5:>ou_+Q+<9GQ=uc3JA=cfXD7=J'p2ZO%[9q5[VZrLTu>SiORuQ,p_u'GF,i\"\n    \";jDbNf9H[,;QYbX-*Gk;@aHS8ZbMT=YDp8;GlNG+*c68%I>OeO^EW$#gWt&#iG@2.RkYq9w$_/)=Ie<_TNkT`)+3v#6gE.3.j5+%?Wc8/ih5R*;O^,28C'>.hQ9)3GbtD#<_G)42IgT%\"\n    \"[D0YPd_RSV:Fhj:oJgVWtS'w`E#dm8_,mN#`%$nWTk_273eFk2MgCV$,(pu>]uOg1I-PLp&Z<_0PC>J<v.w[b>g(du3b=SD4YT<&pGgMZ<ZJUa204AFoeCE#Ju_nL'X;;$[.(<%+$-tL\"\n    \"L5p%#b72mLFql1%PJ#lLi0+E*d/O'%9WPA#cbp+M>uS^$In?c4[T'B#x,Tv-5QQJ(oiE.3rld(#9Fsr$;O55Q_$'YPTKP`+9Xl&-<xmk)vL'vHQu^lf3I^^]3FT^]l:4b`<,2BbJ,n9+\"\n    \"5lCR<P.]@#M=WP&Rr^P&_&*F7MvGCab)+N0toak;V1DW-_Ve'$csV#MUIfG]VdXCsnmVB]8c2H#K3j_##^?R#ScW$OGKG,Mvpm##,c/*#7$=d3L@dB]p&p(<nqY,*PX-j<)_Sj-H&^Bd\"\n    \"2UkD#ZVCs-Hc)u7N=d;%%fh10o#fF4k&B.**2ZX$2^B.*kc:SVP9-ku2lZ+5RI6l1_SBc*Q<g1*4k`xt$#3T%V+*:R:Z[E&=.?#hJ)j]g#X,-).v^Fi^hU`avO`tPlUx=CBSI20LJEP<\"\n    \"W2sUdR;QM2g#8_8l0Lm*dnv%FOI+T%r(eZ@7wE-uL;A#hGCdCamj%K#n,wOY`a_HP@+4MP)5###e]C;m9L/2'ojAJ1U)t+;*9&##SOQp.R]jj1F1f]4'1RP/D:r?#?C587ds>V/64i?#\"\n    \"@4n8%hoAF*Rq4D##mCT/E^wmsf91,)T35N'-aNjL]O<v4[)Rl1[9aV$:*YA#*C?o'O>E^..+F9%`s9^#;o+KRi*k_,OC__(WO$9.0vN/L0s;1)ojBd%:%'ZYe)Jl/EBCxb'nbb<c%E=.\"\n    \"HJe_#WvNR&=,dW.(<xW&h<C>5`PPqu7JkD=r.9L(e3UD4c8LB#8PL8*L(ou.:&E[.?>rZ#>1Yb@fK'.>_O>JCG7Th(4@qFuor]N,T.[8%=ZS]FL^VA(Zm*5]Tb]:`_DR*-YEUG)`'qC4\"\n    \"'f_4S#B/K)&EQ7&,=#F#?Lkv=nLW[>c/AZ8Al(v#D((X6';G##lELZ%-g,T.Me[%#U[bq%6K%xce:L'#PDRv$=?E1)1+Y/,.b6g)va5T%tNv)4/rU%6w0tD#k&B.*^TD.3$lnLA>x0QM\"\n    \"P+lq?D=Z>uF64]#m@jt(kdLO'Z1k3GQZ/I$-=:h(4GNfDBxK*$?B[U*4K`5M^RSk480TxkO0u,)Ujv@+6LL'#nJ;h(*Z_.G)Lke$hbi?#%t;U/$h*wKbKh5MF2f'#1GY##<(ku5aVTc;\"\n    \"'Km8I=Bic[:e$/CGXeA,*-PK.*wt(31ac;-0iSCN).v;-Sk0v_&BsNO#Q_<U-R#)tsHjM-+nsq-5O0:)L$H9M>q1P-wp1P-xU:&OQ[Cf'6Cs#l=N`]uTT#:2_-V'8F6o%ue>N0:^&-Z$\"\n    \"q`V.0b>(u$1EPA#0;<j$qHfa4lEZd3_/cDOdPa.3f`aI)1hl(N%[f`a?3(D3lQi)+vF6V.`<'D3xgA@#%#fe$<fZe$lD[b3v+a9)*v@S#n(pG2Ls:,@rMg?PS)q;.V-LY(_'A>-gjY8.\"\n    \"tu%[uv;w8/,dZb3vLO&#;7JV%8=ai0coP`<XT^`3fh4g1@]WF3K2'J3afWF3EU@lLH/Cv-VmL]$PFX>-E&L/)X-?W.(36N'.fbX18uXn*=n$/C'e9T7jZVnu3=0b+8HNJM4.E>)ljVoA\"\n    \"R]<rdQH@=.1=,8J9k+4g0wj:.5:JguIZm]VL;:$-*o^*[X0Z0D>;il0N*p_'L0IM9AF-).3$E@,dEN[&iF(h)qj[E33=DW-&((B#o%dL:u*Sp.=r&X%+#Bs&Q-g+Y++p+MO0I##<$(,)\"\n    \"-c:?#8n@X-U+:W-4TWjLYot1)*JH##c7v@#k$]/1MFE.hk;T[u7V7+MBsKJ1]$E+`l&%e,1bWA#e:/b,8mTA#R($##e,k-$FRj(&F@C/#UQk&#6,3)#P%T*#-n@-#Kst.#.rs1#LwP3#\"\n    \"4>(7#otgo.?]d8/e2M_=A_g/)P'DOB_n[U/.J,c4dbL+*2b;H*,VW/2)rY<-i$BK1p*,V/IdE.3EK^:%K$HR*vX7%-eX?iMAoG<-UXeQ/s<6u%R;.H)GDh<C?/Q,*'+mdMc0.e-r?q0,\"\n    \"8gX,3;i[@'cS))3D=M9.N/oF4?2(W-j@<h>CP7C#w1?1MlV@D*Z)Id;N&7)*H$TM'R306&B:%@#NXjp%Kens$Fh82'PN#3'vlC`)I:.[#U6^M']wF]#cCgF*O,EA+sk2S&Yfse)C+06A\"\n    \"`6'm&hVD4'w2_w''oNp%Zwns$^*egu7>H7&NWuf(Nts9%]^-.)mGc'&4h2W%&^v9)':][#X?tT%n$h%Om4Dk'L^vTMAd)I)]wxN'Z$&@#L35/(,*4e'c<8@#=:rZ#ItaT%>(M;$Moq.u\"\n    \"Mbl$,H=1S#lDkC5PspU*.WAt#TjuN'KelHhXqWp%@(D?#[K($%E1.W$Ed&i^WFB'&4KT'&dZW/&&d&0&Ag(PosBfQ&n*wW$/wX3'A1Cw,tj]q%hpw5%Ce*]#aGY6s>cB*sijKR&=xVKr\"\n    \">VkHrm$XR&;*rfqAv/X#AZP3'uTk4ot(_N&;WDjp<9cN'c/Mc);8i0(_IJloNX`Zu2$6h(*sKcH_30j'@I*T%=k4gH?c(4'v>_7&Tvp$b9=@;$#&5>#9N_]4K>W]+0M3>5CD4;-RRYI)\"\n    \"r5pV.HS/)*JC$?$4F1DN@5gF4jlX(j]fIAfvef1B]ixMIo;`$(NU4GV2A)ZNL=u5$#$5cYQlmmLG1t4>b*X%'OYLEO)qjM0gw72LX6h*%#Zig1Pke%#NTr,#O5C/#B,(o*7eim0e&&J3\"\n    \"4-U:%YsHd)5NI&4r/Tv-KmLT/kHuD#inL+*1P,G4ko)C&Y'q+M$@o8%#A8I$g^<c49c$s$1>Kf3j&N9/=0w)46QC:%2P3X%$6NT/;47W$a4XF3q01]$]f.'5/^@+0j.8$$H33-,+VxA&\"\n    \"W@1,'<Zd1B,o$>##coG3JY:j,DcP>#wpn-N00.DT[#'b*7=@<$CjSV'DT*c4[Aa4'qq>,*bZgq%*AcY#+fbx+)BdO:m#h3'2i(?#)5G>#4-;QN+2tX$K[d%5(&Am*xTWR'1u%oS$eq58\"\n    \"YoB],:Ks[,(8G>#U<3d*`G$S%>CW5&OKAU1?olY#Eub[Kl:0r/'`sw$KY+Z,2xOkuZS(%0#4FZ0W3q#$+5ofL//I>#I]G>#1HFc+((qP89lb.5ds=A#1m)eF,0Wb$-Ph;-w3B*/H76g)\"\n    \"9O7x,x9[x6L_=F3.%p+M$J>c4ZL3]-,1M8./^,,2cDC:%iVC_&cQ0QC*rPI#ha3b$VMaHZFU.;Q.p2s$-V(Z#=a9'@;pfgWK<vV$3Lq#$D1>qWVUFx-/=0/LABCO)nm0u$oubV-*v8<-\"\n    \"mwPC+Z8QWENZkI#7)U#$n1#C+S-X]#Rso&$>jLx7>`Qs.FoFGMa0L+*T)5H3.u587?&V*3,N/i))XpU/Jj:9/H.,Q'bCSfLCwZ;-%$KJ1,Js*9Rir0E9Vc>#6R/m&/x8F#WO(ua;_r_;\"\n    \"J5%[#8XLB#IXC,DA7L28^kp8oPa5/(P>k''/(v%$6%J,V50M7n<754E2jEX$Haq,)64C.#cuc%&6#Ls-FIEdX*0;hL/P^I*lYWI)b6Aj0J#:-mcEnb4?_#V/1EQJ(cnCA-M5mxF/$@m:\"\n    \",FcK;no.f_)'t$-B[_G3S2*u4$,M7)Z]kI=rUm^XvjZw'eI=`-)9/=#_MQxgLgu(3wl=C#mc4c4br9s-;va.3[UtQb(r$0ufu'L#>Y[OVk1k3GL-7B#euita$X82Lj+T&Gxvmo%3l8H2\"\n    \"-Mc##=(V$#qvK'#O7p*#$x=K.mMO1)w_B#$'YbA#<2@R/tt?X-BL75/]Psw-^gx9.]L3]-_`&+**r+gLsx+c4*krI3_]B.*W,`x$Qd[NO4Lql8Pn65LO6cY#ac.WQ[uVd)mJM1*c,=7;\"\n    \"(M>C$$U9>#$VtA#N?YLUX)R5LK*cY#^F,o+k4G1F?Lw:7s@N<L'nx7/-RZd3]k#aN?o1e$x)9G;q9/^ZH7(f)Uk[s$CY@C#(W`X%rn+D#Fc7C#s21R/BP,G4w(J1(2)TgM`*#V/a'UfL\"\n    \"+,6u7W%i)39pVI)F0gQ&nR;h(nArNXT+6<*apuJ(W;IX$=6n4(,U8hqe9][#]PX1)>)Ol('Epq7-YE^4sOo)*vBxU%=&Sx(h_=h(uvY.:7QAi)YKkVJ:o8L(2rvju-&jUR:N&M)>EOM)\"\n    \"<H;,)DYEQ)l/5=-i>;c/=cOR'i';p7W)MT/;]@A4)H/<&A('/L$Uah3-bW/1fARI)F*Bq%$i)p%Vhoh.OK`QNWxSfL_(^fL2Y:@MSK=5&<`sp%j9@&v81o(#a?H#8xvw5/-@XA#R4r?#\"\n    \"fgGj'x%MT/ObE]-QtfM'-Wgf16HSP/kK(E#_3rhLE)t1)ter0,R8tZqd]g^%11uU&FIJa^d/Gb%KIsYlnp)6.]Ya7Q.sc7Iw<6AO2CL97LA>B$jv-tLEWOjL$:HErwNw5/*vwA#;nn0#\"\n    \"Q*66Q`_r7%xcE#$+PY8&w@o%u(L1_%Y),##=($c$17###Z,>>#h>Zv$8@[s$1wX5&-'R,*l%^F*dl`^#K)'J3?DXI)[1ur-xUXa=%_(KCLbf<BUSA=2#gcr7pmrxA]pa]+4WlAJwDtfP\"\n    \"Sx'H]<6c&+JV_m(959+4mK/.7tFQY*?4:'WVgRO(<$(MlEw2AFea@lS9^k+BYW+F#g,_wr,QQ$L[-aQ/SVG(?L](p_@hjdtThd##,>uu#/vVm/;xL$#JL7%#j2h'#HQPJ(V4=V/W2QZ$\"\n    \"(4aV$4K_q%QQFX$`eEX$=38q$a@u)4Kk4D#NNg@#pH>8@4MpL^2L[D31jZp.lfZv;$wYIqJK8M#o(xL$h$qL^*lW@X#s#&uG,Eh)2=Rv-9lHb%PW=W6VR6]F:7>l.Ub+%kKQCpk#YPa^\"\n    \"tp&,D*7B.qw#_S.k=Tiupvh[k@8h[kb4(s-24)s-2S(s-pog[kh3n0#tlIfLcNn##lY8;-%*&##XAic)-<Tv-gI4j1Ni1S2b>E.3sm-H3C4ChL%WMG)+2pb4R^s/Meg9s.VGiY$FOMsJ\"\n    \"qq>Z,gxi>R$HUV%^``8.ZR<T%[9MvX5AB]tiC?ZFPHihHr/AF#P3,P#0Ap@tI:x2O;=Rs&8gIi;#UQ*=@(Z-=LT3jX9oR]B+l89&6m*f<wHhH<B4vH=Lp8gYn:K$d-F8W#)OfRFg8pm0\"\n    \"d2BSTn`G1p9mR[u+pexB%K8q7lnAr86qrI=C66GIGVN9(k3`T7m0,89ru5r^bN88%)5###IXI%#jd0'#4pm(#`x=((J;[;%eo^I*duw:/g@+w$+'niLPC*T/=XYD4*8@v$0P]C4x4f)*\"\n    \"qhxuEFN3`#iLa-Z5Z>S=AP^Zb#9F1@:R]lJ_DQwd&vfUlu.'8$TgC&@^HZ##t*4=-A_i=-+Y$2M3=9lu>FK[M'=75/>U<#.u(cuMHkk&#$&>uue>*l$rAO&#:[e[#r5pV.`?7f3PDTi)\"\n    \"RVWI)Lq2v6;P8N0@J^.*UFn`aTOG%b-%E%bX`)S#um[quVmmCpm%j8ZD)1=k[;EIb/nV>M5l<Fn@<b]hR?Q9-*R/cV/6.I-$-ljLCXUT1m%Xsu0Uib6tr=>#d;b##/H&##_$L_4LpC:%\"\n    \"TBOA#B`or6>cl-$O^,,2-XaJ1CG#v,ZT(02+(tO')k$1,53+Q'Bo-x0.d2@$W.>H3;`eV%IXwBnO`&i%sJs>#wn_)50wc6:I`%%71<+',i>Z3'te)Z-jrD4)tqPK)FO[h-h^?)*hpk.D\"\n    \"s9-.)RV..26F>r9)e^P:4mhP0CmmN'k3jm/kKtq8X_(/)Zb^quJ(lmuKvrh#e`+5JZ&eS%x/5#T.6U035SbM(]0AhG@Bmo/UpCwGZ2F`+WL@#-0]$CG(>Vm9r5cY'3%v%5;n8Q13ltM(\"\n    \"]94EIv(Nh=:3v3'RG^88VoInCTSXaulL-'nYSAA=Oaj870GY##J;W]+FpO`<BcK`E&ib%OhF(##28QW.Yt_F*&0CW-HU@8%(@n5/25Du$]J@d)U<Bu$DanF4D&>c4%nS8%:.Tq)Kps/M\"\n    \"Xo)T/YlE<%FAg;-'RViL=/^I*=L<a4(F$.Mh8qs.OJm&#Nh#I6.j]+4%*([-7Ot63*aNT/s(H##9W&`Rj2k]FF.8x]X2[].a$=x#Q+T+Vgf/21<Wub(Cd^u=EC@SBE1;/)PI+T%fKP+V\"\n    \")FCQ(WP%61Nc'O'(L0Q_q+ce3>gkw?#U,'-h5hpn&^T36D:0eEi26)6HfOi0N.]t11nrA5H9OE$?Bbc+)4&<.5lCA5gOn8/(V*)5B[hlAH2-Im7Q-]XSFJ]NxO?;6gW:;6q)0*,9XAmC\"\n    \"=+tPZ7>PC5Zs$v&9t->6.$QQ#w[I&5LtD-GE%`5.=fe58^15819gx_#Oss^>GNEm;c5hKq;=J*)^tW[@Dx4K1_B#(9::A6&cZr/W/e+98[rSV0hqA'5jRkSu>>Dw]&(A),xDo:C&IO]-\"\n    \"ZqPn*r)w^>-4fBJru3GMm].7O>3s+Vx4ct?xv+>%mV2>5'TNcDpui+M]b>K)'K8f3h3))NF[p_417Hv?R52H*hiWI)LOB_,ku8+4(xkj1pC,c4le/g1r[=F3oUFb3S%(f)%lxfL3<+Z6\"\n    \"J]B.*28P/M#HGA#kIQ1M<WF:.n/1#$8;NV?J8YD4u7D,(nASM9`Q%qC,7hk;cAV:<w.l`>'8k9/*'#q81RP.BDXmh2Ojpp.M5qY#V_j@t&W8f3m#JdDHVW;6[tF/(@?:g(6JLW7d/14:\"\n    \"Sr,k2bU,1Fvi=Dm;n1E#hN_%@l6VK,;G123YRcJ(cpPx#up4U8VvGe8@/Gv,)aZj'kKO%,Ra(h+c2Zt1+/._uP8SpIo%^r#mnib*?9J,$%@u0/(?bd*[+Ka4-Ld)4'1[q_*1h%%2^^##\"\n    \":t+/(Rdw.:]Hx7I'.Pd3<iXI)kMr`3e5e#5Fqn8%ig'u$Nghc)pY7d)OI=j1qC,c4f[Qk%5T@l1o:gF4'`F+3^]]+4n#IH3d(4I)1oh8.VJ7&4j0Ox-k]x;%EReLMU20i)BMrB#oa]&@\"\n    \"Z^Th5J8)j'VgScSRImrJ%^<2'k.;tQruON1_[lr9*m#B9Yh$T^ME#XAwJIK=rI5Tkd9vR$17J3DahWC,L,Ea*pV]pAjU9vY$%X?>QNRIq5Waf<SP6/*X0f*$K@$`QDv;2e8c[60vj)V%\"\n    \"drD50EYRM1*'J1g+H&r:2fO20[:=>$mI&fOsZMCacT22Bv3R;@sT##]tUF?6nEZD#9s-s$28u=.69VO$=s=I$TL))?F>F,#'Buu>LlXU&>u###Sj^#$Z>-$$6Z)F3;CU-2ZT=5&^D#J)\"\n    \"c*3K#jNi+i;CTH2.QV+rG2741csv_uJW-4$K68c&<Q;N0gi(,%@'+&#m####-<Tv-YrCZ#Ytn8%a%NT/m7o]4A9w)4onX@$g.ofLO:8C#[`JD*2r-x64=S_#kmqc)sliO'.G*X%Z.@x6\"\n    \"9eX@$N)Tl<[iP,4eRb]+pe_[,o#B7/i`cZ67P*SVYDcju999W8Y_.W$tDXC5YGvT;f_qSb;+h)3?=N6/IcLv@Xe(sUImhG)FV/T8Sq/iuu>1^#pCt8rWx)I6lU0Q0h3u^u#joHU3TEjL\"\n    \"$lT2'q&i*%@PBSD,>WO'c$0GI<VX8U$&###[fg`jdC=gDe6h-M&p#;/,Q=l(KjE.3(fPv,dCXI)q?`[,)MX-=4=4@$ESw;%PTk]#P=@8%o.J*--IYQ'*+D9.q:gF4Xc6b4MD^+4S^,,2\"\n    \"%L5gLY8Uv-(oR/hNjv)*Pa:O'JpnX_]oGF=(KP#-&?Z]44Rwc;$pas%j8dR&7>cY#lB3O)cbNZ#[saSp^U+]73(qT7TCXS=U[E/>M)jS&+(X5&%3DXIA=wS%SUaB#EgZD*4SYX-BOc**\"\n    \"OB0M#YXVd4L;*/<W>)c5x0ZT'j%`V$fE9cd<3vu'6q.x,pYPMT%5Xj1pKKu$k5F.)/Jc>#'c7$$R[Su.<Zc]#>DlY#FrHd`Ln440uo:?#Fa2,))5###jgn##Js95&Z:PV-D?<J:)6&##\"\n    \"RA//&-ghC&hlcoRJ?85/o_)Z#jvBu$Dfn$$Wu@Y.IsFU.MDJ)*Enn8%Oqp6*K[13(#EIb3p;H70SSfp0F;sF3lq0O11'aqodX%:.-q'V/;5w5/uoSCsh9'lu;/^:.xopw6BB]>ucCwtb\"\n    \"=>2i[302q#tv)j4I&+3Mx^bO#6LSO#NE^5&XX5r/1lFlA_VGb+Di%C#f)>U%SYVMT]0X9<(DN5&e4aiK?T)v,8>vFW$l2S7&q*;^6u6uqn-hWPPbF>#x(>>#5VY##A($##BC)?#upF3b\"\n    \"?>r#$]R>^=CU)P(#^(9/S@4D#pw9x$/[vuuQS@P'K7DZu-/qw,d+BF*VO,.hk,u#$#4K/L]QbX$T5#EtX#:U%fOC(jg.:W-D&4E$I,?3W@<@0)EH&$#uX9^#oOm-Hn2<A+EH9fHAx`eH\"\n    \"Ci=B#E@Ep%eh4d6>6I+ijvBq%twm10r%L8.wsf]u.A<+D,-ZPAK2M@K,43f_nrZQ364Z30x:R`aFC3X$EDi:O0D?:m_P1t-#u7nLhTA[#Yw/+a0L.Z$j_)e$gc``3QvQJ(SgJ,34.wHf\"\n    \",,c[tXi?%bdDDO'eHqT7_Dw`*cG4[-`eQb6WFblAPKhRjpDW]+V'q?-bC:[,0b9a#c_-##Q699.O;O=u;b*W-_5>F%3'ic@$N?Z$M8tr*6*qW-9@l)$kVvv$-8[0#XQUV$[GUv-?]d8/\"\n    \"xH:a#twX%$sf6<.t?]s$guJF*`;UweSM?p/q#fF4Ufjj1U1<u.*^B.*gSUe$(ZVO'XCj:/x[K+*,MhkL,,Xb3-sZRC_D]JM_vMw$-m8^1DpFe*qJ4_5V@H>#[(]4AXYG>#vDf/3VSR.2\"\n    \"5WMBYHnRx,jd)hL&:eY#G6Bq%l3FX.;aqN_OpH`0Ml@m0fg3jLE<G]#^&c05$,e'=aH.iLu[I?ZNBk:.)6j0,E9d2(vdNd*0,j20(ZL>$oI3:Iv>L7&J)ed)TE68*QAA>,:fs<%5B/],\"\n    \"Zt86&DV*&$G6Ob+bNjd*SVA#,x7L41#3P]#)TS_OXLjR&I,nd)sn=uL4jT7/(1j0,-V`V$w;+1uaeK7&h<[],jR$##$&###97jrm+>NfLB]ZX$fFn8%d(4I)x3vr-^gx9.Q_Y8/+P`S%\"\n    \"YD,c4E-m70qcY=$$@O+3J[Vv#;2N1+j<*E+axW;R1sMZ7hI@jF7L7]kSbqP8v[0E#-;*'4204V.'c<Ab=77F%P;H0'&%8dHGpM)I@ml&#s]?.%b>uu#M,@D*^7pu,<@,87Xp[i9^kYg)\"\n    \"&hq,3hhjm&/8s9)<nE:.XP#<-`%6]P/:#gLU9MhL0YblA04N`aqo1i:,2EKV-<E:lG;4V-ng`X-;D2`&m@9)lxkx?LasI731no7//L.U.&XK<Lr@pV-L$m4+$cG]Ot>ks7u(>#%S6[0#\"\n    \"I,>>#,RXt$(W8f3SIi8.]4tB4p>:r.aScD4hlE(4?MeZ$Yb@W$NjpwM;_XCs#2T1T5b,C&XCka@JZo+`PEU?`,.:^ul?P>#?F8##T[U/`**dn]:4x:.P58o&k)e'&G19U)O,wd2(dZ(#\"\n    \"Lw]:/Ak3Q/AHaa4Zo7>8ukXI)-S8U)6FUhLPV5J*k_gb*wjIb3S1EH?SGCt#SdD)>'tNa[)`L67)G[m/ToMPqU$0Q#qIUT&8f(aKIn5O'e`FSK'XIH?A+xJ5^.UK5aEi;?#`2c:6Wv;%\"\n    \"tNa%=Z,-O(;7gr6s$+;?Pb`uG].$k1:@i?#^4^F*PwXw6=n+D#o4K+*^s-)*46tR%VS/C4of^I*7c7%-ahh8.R=^I,xqbI).Gw@',KoDcdcfF4d`eU/IqL`$:va.3/+5gLw.<9/#&AA4\"\n    \";p=^%$*cN)*.KLX1G,(+x96k(41x.+WYgKr#iHU7S75nuUt5rug@>iFwS.vP$:u2)V+=dtPET6&E%06&Vfg>&.;)S&E%tp%V`T#&oh,nAv>9I$#Fr$,08gV-ouE[0KTxB/3Utp%],fL)\"\n    \"mc1rE&t]W$C`Y*.a/.#2.-Fn<4u7_^uJZ91H[`V$?&u]79UTE#;MLlLTJ,lp*Dg;-7:)=-4PvD-,n4(.jjFKN-C'g-n@u>@[kH##mcZ(#N2QZ$s[EMKuP8N0C?lD#&1CF*7Q(Y$7-p8%\"\n    \"F=3Q/E1#`4XMe)*ra70)W&]H#%g()FlPG&=bQs20;5KvCqY0CS)bnXl)+vnpqX45q>OTA#4QccH:-diO=]Slfu$>o[(CPhjba=at6:j:$L-SP8ribtJ+LPT;fIC(a]#E]tEJ>^u8BXT/\"\n    \"g87q//:jl&$i''#Zr@/L2/^Q(Osh*#;H4.#&`W1##Wx5#Ztgo.acXo$eCDs-R'WYP79EYP[21s.#BOZ6A2Bb./k'C0+=UZ-@Xj;$umf*%[<sS.j^K>$n^(9MB/:Z-?iFB#p#baawDBI$\"\n    \"0r0^#70L40&r28/iW[a+-^Jj,)&GD#Jn4uu%&[Kubaue<sh>2'pPul&>*mL3)eP</9MsILxMv[N8V8@#Hs><-@6.BOnb`D/]RGk+$<3;3I2n@'CsS>#[*iK(<1Uk;7*J^5<Rah3mv@7E\"\n    \"rdFoLq6ZD-qx8;-.FPh%w^CG)x;#,2]$%##OZ'u$RMmt$O+p-)jtuM(b3i0aIrd8/h7K,3r$eX-b.#_$/dC(&>^VI/'-g[u^#K)t-U4Sn'>G##WbOF+aJTr*U49qu:di?#fwR[#w&ms-\"\n    \"iKP+M@u7%bNgAE+<@hcD%`Sa#:pP9M&O,L1QNcx#s`Z]4Zm>h(xA^e$#MK`N@rIiLCQcI)IE^:%U#LB#Mw75/7cJD*gHILMTo@A4OVew.tP)WVfhDP_p8_Q#2$'IWA]*;QMD8R*ZX?W#\"\n    \"?j'mARC+^uor,UWu6[e-qN#>c()xYQ+wpqL0g=W#2d;;$XXJ1pqcb##AQ_c)pvm+D83LG)I]OjL7/B.*DRXx[A4kp^x%iY$J8^F4)*4L#0lF+31x4^$$XLg(=@[s$URk%$YkRP/v4M_&\"\n    \"Y*.0)xg;E4qSID*q.X_$TfA_4v>D;?W**tL7&AH#L<&a?+A8&@io,K<V,c(6LpX?@w/.A>5uiu$l.w;%C*(K*^flK3fD(bcX33ME<f$4<1)[S%PcC;$RSHbHs4tet]#sT/Bc<5ABb6j8\"\n    \"=vRQ0cKi@IdEX%I&5SF%Jd4u#NKNt8I.TN*BX(hLkdrG#b)<&+JjFv#.o6s$uK@x,7M'euP,<D.m8MCGndeY#/IU7[mM7@-pnSQ#a,c)/)1F5&'TCB:6QEEuwuJc3';G##Ta]*%b5###\"\n    \"-Mc##Ke[%#Xtv9.0^k-$g@?lL'd#[-,jQJ(pBr8.HDo-)+J-j#d55MuhSJM9q&x[uZ10wi1Z%2Fnx#D<^o#.$VJuYu%4JRn0%bYY#[wC<VtJ,NstJfLfQnuus+1r$;);$#e&U'#[O>+#\"\n    \"Xsgo.G4[s$(&MT/HD#Fu<wtD#+:RP/=%D;$ctchL[l^I*x@^Y,4.i?#(#;9/Tg;E4inL+*[:*H*(ChhL+C75/78>jL(]+i(1=`9.mP;^4O$+a4M_gC-a2[W%[Z+Q#<qCE4WW]<$jiR;6\"\n    \"[i)p'KI2`+g=MXID@):.OX*T%:@p5'SUW'>:/N>5,O=u.%N.>2k*w9.Aq>De>+]@uMNg`5>?ub%a^]c;<Csv#?AM0$kL8ucABID*Fhe],td=63H_9K2o&[*L,/^<-hFGW0b)dN'r_Ia9\"\n    \"T*06&uRco'rm*s-q?l9^)VJF,6E^j0A4*lhe&H7&FFrk)QU$O(Sq[d+>N'&=]8o<?eCCa+pFj6&nxQ@b1o?7&3>MZ#-8@.2^==*Z:BIL(Qm1)#ZLOgLR-SS%o+C0G`(:c+sp&/1[w$##\"\n    \"xm@X-L_G)4hbtM(:n-^O,<x9.;S<+3rBMk+.`:W-BAmL:3o,[-[)#YuP]K<L&MafLOXQ##Yh5AOZeq=#$)^:/O5b=#o;uV+5tNl<_+=+G1fRn3tVr.L+-+GM[Y5<-BA3v5$nS`aK1r7/\"\n    \"RxkS7vIL#-$2=tt?Y_.G88Z5LgP8(#93V;Z]Lro%&/3>5um%##Fi80%Ux]_4A=vr-+FId$rHuD#CcK+*S7v>#sFCkLjNJw#l;hW.*m(?-;$]:.Px;9/-FZ;%65>&OF^.)$F%JAK^#ge#\"\n    \"F1GwKqD)RSOkR5nUN8QS:*,n&-#GN>Bc5e5,:4E&xY-K#LPpSM#I]l&ae].L.IX.LSxUK(-iUn#E-F]#/@<QSM$E=-ZthJ)Two0#mv-4'+;LD?D3.h((&9U%Z4Nw66*ev(P1Z*RP]tm&\"\n    \"D#lm'_[b<Vvkb$0EZpieb:fjL<L$##T%J/L0c68%AU#h1X=#+#/$S-#``-0#tB=+Fp8pV.1x^7)G(g&+^s;EN`R+Ls%jK'F.F^;.dQr`$+IL,3[&T9;95k0E%1*+%#'5+%/,<X(;tH@'\"\n    \"HUh#$p,BR;r:F]u)d)gGRUQ##3Y$:;C*fh3u<kL;+x#gLVeH1M/@v%.kDd]M)4P(NQAYTR-]jIL`[3B-wO,W-5+FO4^ahR#j1:LEDXb@X6L_#$Lcn+M6JG,M^Jh'##vF:v'AC7%MvK'#\"\n    \"k,>>#dobV-(6Hj'<*5N's3vr-mZU&$S]u_5P3q_4]xql/:&^F*&QC:%)iUP/v?]s$q29Z-ZQ(cH/03i,x@;))]Zw7.>,[Z$fWjV$umL(*kI-9.hHSW$ae^O1,RlB[Gr@f*6]U;$>M%w1\"\n    \"OVKiOP'V[#,d1Zu32(#$[J'C,sq0mK3,(,$jEkfua%l.)GbuB+ZL,%57`_:53koR/uKK^9mPY>#++8WE_=Vu/6gS>u['Q,*+l;8/tu]dW'>cuuYKf+%f9cf(e-el/<^K.3okQX-/O:E4\"\n    \"e4n8%@d<c43k_-Md'<?#9AP>#wn@sZNe_F*Av+K-Mr]mA*h,<qXB+x#?N>L<*+bigswqi0V[^809@UGDR];%kO1O,)[Q^n)mX6,$1U=oRC?/J_6^o9.H11Vbxt'#,<='VZpu,c`OZ/YG\"\n    \">eiP/9.8V?&[SG2_6JJ1ib^'+cUuFD*8###W4$$#[CVS%J)[`*(Sfr6q$FV?Gf98.-opr6x+)Y$;>:Z-V)q#$KkRP/n3*v#<^?Z$?;Rv$GlR@>s%902u4WF30>Kf3.=/+4L8^F46B,<.\"\n    \"-nTD3fh_F*kB%/&#o=0l@t.j^HNN%$Bq/m&;qcV&YKft#lVqi'hvEuHN:'Q#])pXDT06B97N$O#cU<:/#pNV9`i<eF'SrxO5qqk1Z*t?#gL#0*l/F2hRx8?LGDL=#$Uah3fh.T%ZEGs.\"\n    \":H:<-3Q/K#25VE<x]C_?R4/]uQ$IKu6wv<($ZVpCgUQg)8Y&T&O$DSIO6:-+<hnX-6o;jTmnr)BIE5AbfKBC-'M,W-B=Rd+iX9N(hHai0AUGS7jRIY>?/8JCaZ=SIsVf1^tdj=lwLH8%\"\n    \"d0320[%DW6ht(G#uI31#nG5<.kmqc)5WLD3`l`^#uT<Z#?QNl(uk+i(v4WF3vu.&4ULD8.Y9@+4NT/i)dPi=.2Pd'&2rbF3@=E:.)`OF3<5#c4i:AC#1jic)8=tX.hD%K1=J-W.>a$?$\"\n    \"+gB.*1;%@'_@3(&79wG*`id8/=W8f3QJ,G4G8pF4T2v]#k#L:%k8v;%xTIp.;U^:/KL5gLiPP,M&R8f3(WSiLMQ5W-ZD&RN:kHv$x.6h-]cM*ICF%H3'VZ1M-lXI)1TxQE]f)T/ebrD4\"\n    \"Yw3eH;<d05.do?9:r;g)j0ho-DVYLk<t.>-WM]b-fGF=Cw'J,*ZQOa4DT#w-o`C]M_$w.Pi$/>-+j>D/v=[v$sK_hL*&lI)1rSfL/mZ=7sO,G4/Y<9/D4ji-mjXtA,n2b$ZObPAcd>n`\"\n    \",&'iNc+3?L^@0NW.28sKcVN#A<rk5Mca,R`cv8i`6;LJCEF`v#O.Is$7%7s$9:IW$0Mc>#6-N`#.PY>#_CF.)t7+i(o(cL6Lm2DNL^rhLoS%`*D9tU.Z?P>#PTr^#*GlY#-P(Z#qxXt(\"\n    \"]p]b`B3o=-x6vc*:^bY-HQ+^,kpOM(Qc29/trB6];fG(+qo<**V%4/2+_;)+)b3Y-A5Hb%+p?I2T$s%,?v%I,Z#cY-oxWe)+59_.=mlZ,qTXT%oaAR/-mMO'p=9F*p].1(-3OY-=hxl'\"\n    \"TrVT/E*rdM+R@A,U80X%A^ol'q,,',ugfnLHNME/-]L;$Z1x+M.u,=MQUd>#fHEV&SZvuYeGMU`8FKtN6_eI#F*nc=XmWpukYrH#N9%UJPbqnuKQQe-AdLqLlEx%uj/cJ(fMeH)K=DZu\"\n    \"l@N5&.PC;$7LwW$Q_Q(+cU=x>EAdb%F*j)+Ho[A,=bC^#VuRfLq4RE.+;P>#@w$@'m_ai*r:5c*p(?:;:Kg3MF'P=(q&Ds/xoQv$BHlj'mC0b*;M2C&?&kE*tLK'+Cu-d+#k@Y6+05$-\"\n    \">((+**FM<-/i/Z.^MB#,b$GS0Yn`?#0>Eo&^VS7N9**QN^DH7a9wN?6;`ffLs`)v#.SuY#sCbA#&+-$$.V(Z#UuRfL.bJVm<;hW-s3K&vcu.9&OJW]+/+(582K;MBTb)>G+((AOiI(##\"\n    \"Ek[s$c3rI3R<0r.F$9K1X*gm0END.30ubF3<i%@'p4$Q8XuP,*bBP[$2e<W-YcNC$CFB(4oIn20D_i?#Wr'W-Lam?.80%0)Ba><.+2B+4Z]:.$MfnU/-u;OFKoAa-d1XT#/_7>6IoH),\"\n    \")w$n7.S.,t45eXA62v?6p#;E#6G.D,0OM@,k/SB53RPj1*Vu$,UfmO0`qnX73c%60VSFm1pF&q/0aOq:5N*480i$ou4B7[ud?iD+_EB;E%23@SSf##:W7paPB0I,Hs@#R#[?KR;<c+$8\"\n    \"FP)g;=3M^4QB.>%MYnb#4sjD+GRJ5'$Mhr:Y_>H/SD_c;u]*L)^>V0(OxMt.$8j50R0Km&?;r11GsV80_5p/3`6Yg;?WjYC?8)j'c-dYL^W`^#=aw`%cG5?#:axqujk]x?3U,`umCY*<\"\n    \"9g4l]v7o`tYe51<,3M*MvqJfLA<[q7*.]v50f1$#FL7%#cKb&#.,3)##I`,#*$-;#$Pl>#R^0B#qvI-#;FoU/PF@<.N#G:.TRB(4ExrB#n90u.%VbA#F),^$_hCN(P*s8.TA2T/.cg/)\"\n    \"X;*F31/NG)(Tc8/Vnnq.(n@X-*n,O49%1N(v/v-$qYWI):k>l$J,0J3ex#J*osfX-4SVC,C+7`,LThU)9=Hg)uQvT/O>[&4O/6<.2v6@'qRo3iJ0)iLBe6g)=5kvLvg3Q/jsx`4Q*SH3\"\n    \"*lOF3)^B.*/54C&eN@K)OKOA#D.Y)4/9x/Mn*B.*7k7:.jLo$$+Ei;.7.9U)426N(E]058L-+O4QS7C#SrU%6)jTv-CxSC490Si)(9*gL?N>g1BK+;.V'cJ(FVUs-1@%lLk]d8/@c.R3\"\n    \"4LXD#]uJL(p2W=IBYuo7;)`kPSm)pB[2If=CjqP0FlW^uIn.T%&k&m?OLM78H]/QM#w&P9&HT4Eax`lSt-Zc*?`8t%Ed4(v#hs`<]w`euM2a-T&+4/h#H-T%cP8`4F'0@Ga2;8&]+gF*\"\n    \"@Gux%ri)xluj89+3eTL9Ax8f2YUAn0M%r:<Nu.T%A((`,xOK[ug7Y7gJ^5Z4NYiO#e#mngAbiuZ9f(Z#5%q%YM_Re*P'[q79w+w7'd4`uW0QC+xKI>#^u3i(u;ws2I2_HihP'dRT=fa#\"\n    \")r[ZKvv2.3$JcjLiuBg2*_1$+*fqd-]:Et.qCGNLGeDJ<ip/TM(KY.;qr#?%2#/p&$tAV.l]/0FRCgY>djUR<gA,G4KW?R6$AQB,r6)X,wvO72l@2'M/hRA62PG:vAR=B_(/g[,M1DZ#\"\n    \"4.@&@;9o`?i]qi'T)_x6fJ(v4PqP`#sB4m1iLVnBJ$OM*>`cY#hF``5M54kL1KihLbL<<B0?HQ##(uZ-c#_w'''(<-s6mCNUe[;'NZ$T%Q1W_tu#lp%qW-P1iloH#Ot^xXQZY-2KePu%\"\n    \"v/Q7&G.si'_5#VHKvZm/OA,G4kM%fqPaxUH2Pg1()dPW.r1),+C%%s$4AtB.:*6n&Ynvp.mXut6Cf:Z##Z[QeBMkiMAAR>#_X(@,Zd4Nh$,,##uJPfL<$RQ8cACV&^O18.[lL]=mxIcM\"\n    \"r)RrZQm1Vdwd8A=8Q5s.5wM<%x3YD#$]`V$x1md3B4vr-ImZ)**[^<7AY2)3*)TF4KLmLMNS6<.*M2T.VVAd)P?f>-MPhw-3^s/MMLit-4emeM@44D#YK(C-ff-x-$R[LM/k.H)8Zr].\"\n    \"k.i?#7G?L-pjGx'(v-^3fh^,37sq#$W(r?-Sdqg(mao@#LH,B,o1K@5R#(%7pato7)enG;LI7@#h+b**5*iH#lOFX(^KJw#05rQCPE/>66CD39WV8i%28H9%%bvJ(Mo;Q/[5p:'0:1'#\"\n    \"E/#q;D'<IM=;Uu&tHk^-Jr^$9Z)kP(A?7)k`D<HMv+-3)nNL_$nMxiLmngn/_t-;:w4*`#f2I@-dFw[-:bPA#^q-d)RjHLMQta_PP0'[uYt--)Q>%w#kOKV#YFUW-<8Z'6LQvn&Rmhc)\"\n    \"2Si/U-dRW$vgEI$^:T6&S.d.NMDD<HpG]C#HC%@#?5#R&4,lV$Sd1,)MYuNF=P6]kx7mW-I#&32_]`8&ejt(3neeu>@]K`E#lB]OjL(##Ek[s$pT)*4ont[$IuU5/(xkj1-E1l:0<c>%\"\n    \"iL0+*oAic)M]d8/E5WF3on+D#mTIo'-FYI)1@dKCs?&]$oGUv-%a><.Yb'C4$P=F3,PI5J%=Wt(5_eLMgCgg%EDtH?.ZnS/nqg8/.X(u][k7f$<//W6.ImG*R'2A5Oma(%pHl0pCA)?-\"\n    \"-Yhm(47rn1T2WW/7I9D=Rq<tA.GfC#?/DTL^EVt64q#C-SH^N0u;h3'1H:6&:,_%5:2mDS>>Vq/=n6Y%-:,?-;(P`uC2bm1G5KS[DV[vAtB_.Ec:q?5lCLF*q*nc;Na#B=*g.<.,2a]>\"\n    \"A?-v7nMiO'DL1G-FLwa5L;kE*(fFi(bG&60>EqONpOc,D@bH^,3wb)3;(h.$Cuw_uIm5%-U+c+i?p`f3YV7lJm(+$5Xg^@MS)&_uU:2Z7,KkH6_xo*-1LLR'&C^5_nIGo$M`95%.f1$#\"\n    \"$Ja)#Mc8F*,39Z-0Zc8/a6re3oNv)4MiXI)V69u$WLd5/ZI:E4j@u)4$F7f3>(>>/n?vg)^KOA#23f.*08=W6;?T_ue,40S5b+/(9M<D-uVxX%-RUn[OGZ#>ERZk_ipjC?1*TAaATF+5\"\n    \"FI6:4cTq3+d1Alu_kmL;$,e8E.Gp(6IZY3D9k_^+._gf%hr_pL>hEL-`T`AR:QE%TX1'/)%>l(5/veh(oa9DE;FG&#$(6?$#&5>#Iraf/`^''#vG:;$s-sH3]D6C##F/[#'(L`N+hE]-\"\n    \"@qVl(b12Xi$;=GM^GLEua<%Y0)mXj*KCQN0QhPj#mxvcF(]r2MTD%T-e+ob1adD`s=#%TBBAtIL6#=ns4q>R#0toIUBL0wp;*G6sw.xfLmf9e$r=F&#,-(Q/aH`,#8%Fb3'=Es-wh#c*\"\n    \"^p6@P;.ZV-dV_Z-Jj6d)XSU69Rrac6RUw[-x]DD3VW8x,v:^;-N+0bGcBwTKxQfT%.r>V#%;u5&LDC9%a^GO'waH)u:3]vAdDDO'YF:q'0;PS7D8uN9$f8h(rX;G@,#EO'n#Ln3]@`pH\"\n    \"91*p%pc<309GKxIR]%/_'v_$'&BY+/X16aX85>##Ta]*%S6[0#68E)#m,>>#]q.[#Hjq%4hqC.3c9FA#04vr-ZG+V&cf1E4Rq@.*h&ZP*$iWMK=^.K54p`W#uD2a=%T,5(vKt<:R;omP\"\n    \"X7ss$RZG#u@9rV%.1c;F:/Y-*+tjMeX(T^+/<U*F`)3q06jh`S4-jQ9?:rv#0S73-W%1GD%6+Q'7],qi#87<.kmqc)^^D.3?2xfLT<Vs-gHj;-%C%q$sm%J3m*R:734&5JGmK#$RVHt.\"\n    \"UUd4(T<c05+qk]#KD,G4pM.)*fUO,Mw9:[.n,Ih(&;[@-_noYEH9<ZB8k#wAO^j`3l5q:;M7'QARm-a3uM[*]hZ%.?4]bP&S21sH7l1Z#/An=-j:J>8KPVkurOn8Z6pBj%9Nj1]$ks20\"\n    \"87E5&Rl&=UPWwJJ4A-#,pC`G#40$%FCFLLXJ`KpMn`_FZg(R>#C`D:82b`]Ugk2$:`:px$Jq&Q&Ab:c*otwo%LfL5<P+JS@c00N0uYaP&$[G3'^3F5M,Hwx44MpJJRsLfLT8h^##&5>#\"\n    \"0GY##oKel/9?$)*Z&ID*^nr?#&Y@C#VAqB#B@t'4D+GPAME_s-[Z*G4UpKB#?u4N`+EC@&$qHB+:,[@XI:#5v_7L'/pcZnMZb6hkE*eo#8(=%b:6(nul-#`Dm%NPgWYHt.:A.##)hiw0\"\n    \"vp;b7GSlHlAD%NM0dM7#_'Mv$`=%#1]pB'#mp@.*S4d##>a?T%mv)D#c?XA#)*Tv-Q#6`,n1pb4ftjD<Tkk^u8Gx#Ja/Pd#?Z6+`&e6G#I-iEia%lf5:tex6-+L'+(n)RDxx7W9DdAxO\"\n    \"3g:'L=7WP8CAUb;nDNQhmG^2WHmO)3)j#98D7Zm'j<ZE3fYO.#,rs1#:tgo.C]e*3-NYx6w7.H*P]PLM,Gp;-LIGHM/^CD3f*901>2d8/HLD8.[=@8%PsO5S$.;8.SrU%6qs5D-PcjfL\"\n    \"#;/;%h+A&4_G6WQvae##E_=e<Y]rl0%h]A,Hm;O1vXqf)Ggb:.Y)-8/m;FO+dYbJMK(w<.tcON18J-B,PM'0M7VCLM[(sl0GFx[7WZaL#Th:+GJ(Q*5(ww$,EB07/$,'''X)wIL1CZ`+\"\n    \"-lB+*8_`%,0]b.)/khhLJ>b+N:n2`+Ar'gaV=J&,nc>]PRwd(+fk#u<TRLnuswA,2IF9e;jLsC,QE=#-en&W;UEw(#%&>uu[jUV$SBP##OMOV-Hf*F3`oXV-+UMW%GAr.LOIB0/`xC`a\"\n    \"GO*C&%@&I$M3Eh#NGNDu)@#29evlca:7'L5#<b$#Bumo%Q4U8.&-?/(JpN1)bUI8%E]e*3<l>##[X>eux<BpubxCT#kux3$]:nkWIrWT#1[%)N:9o_I24lA#,5K01i(djun+r(WIMwou\"\n    \"a?hK-5]D*/OZ'u$RU]mC(JMB#V)ZA#Rg;E4k&B.*8;>=%)@=qIx:FB+wDi1B^/S3M&TIlf($Oe)M7=h(r5A&l@'_L(#_pb.gaYDMLnqj(l/h)M(kd##8EZlAU[SM)s`[D*Vg'u$G+kw$\"\n    \"IRM8.jghc)^^D.3`aFD%BMCv-`?7f3twC.36XqhLsY]+4`;nW%tX8f3:'PA#(Tl]#9)MT/oGUv-D*K6&NR&Y.c;ZpgVh+4<Nx[`,fq6#6Q7FuAV@kaU$aWc+O_FA#9Y3SR5CT`Q<18DQ\"\n    \"WI&&6W)FoAB'GA/eDCD?_*0w#;LKF>w5<**6%(O+'8Pk2^:c#%Rgxa+2@SSq(48E4L4fQ<+n.lDq/X@]tZmjAR7*-.*QVvUwL(sD^qx>/YdH3N(5V@d;2Z?6QMiL1tBW6(KriL$stxT&\"\n    \")I-jB*'ic)Y:G'$^c<,#6->>#YlR_#X48C#2*kH3PXd,*jeNT/W%H9iF'r-M_12#$^69u$ikkj1&.,Q'@W849uB(a4dOSv$;jE.3v]H;%)$&f&1V*T%OckDoF(0t%)A`X.*hLG)p,D9&\"\n    \"cPwe<iMY3BT16-3#1](6q0[@5`V:7LR_9<E61F&[h<CQ)]2m^G-6SpWI(+s18/H40Xv6M;eSGWDjphT%UNMoZL43q.Y0pQ&23in')%iH4'YiwG@S>nAZ3Zj'2jCY$dZC;24^_;:7USBC\"\n    \"d]MQG26?(F5:qiHn/HCI--8>@8&ha+QxYcCJjX&#SXsYfO@$##Q3=&#U<k^FgwGK)_2,x6,c`$'OqQ,*NII8%dYa?5Ue.[#cI=j1v09a#soq_,OfL3=OJQ#a5s.+%&-5F%;$?iK)DkFI\"\n    \"xxFn`<eM*Z<P'>#oa&<-)fPW-LXsU2_[Q*=q3/tu>jk6@R]F]X'`6q7kCh'#0iUV$6@%%#_QZ`*GtUH-Z5Xf-R`0r_*h`[,HX4SMDf9kNw?45]CJoA#DoUs$QH'<-&72P-1Vx'.ZOb,M\"\n    \"eCFQ'M2[`*V=AS@ESXV-Vq'E#?;Rv$Y^D.3/%T:/rcXV-[jb=$AX%u-lf,(F^Dj%$iL0+*S.`$#W97f3diMB#d)UM'AG+jLrME.3b%Vv-<)'J3L5vS/mZ3T@NW?A40Gu@t4UN<.,pv5:\"\n    \"Pv6[MPMfw_6)1>GdL>V-`cnX$PA<I6(<m6&+bE:.S]tP`j`7;6TnLuP]mlU9k0iw(t>p$u)tT@tWF+nGcJ8Y+5<,A#Xa4Q>B3ST%1JpJ)EPrSCOPwZ9q$BJ`jLEkQ<3uYR;gw9D1obS%\"\n    \"IRK=u2#%R&ODaPA=+HR#v%3X:QAUJ7uhwE+WXG8%IlC8%m^`d3xB1tLi8#]ukS$##d%c^%dkfi'nZai0oZ%##(uv;-6i(P%/K6C#:5Rv$ImZ)*5HSF4]*`+v0YqJDovsY-U*m<.^ct1)\"\n    \"Qw&?-hFO.)bVq8.(4k0E%'(<-[Wa8.dmcO*Ch:_$<CR5/lZU;,u./U)rWf[#f%v:ZmbOZ-RZ/I$T6S.DO4g]+Awc]+_4QO*#omYo#T(m&.7d@,,AsILJ+S_#GCs%,lP%S@'RX34pwM4L\"\n    \"5hd_#`s4J#@MdG6#YBbursxu#@UtdN)ZW`s]9]f111<-m8?0W-616$gTxwU/mNv)4NeY8/Ammw$vjZV^40R,*vq-x6@*'u$?KZw$7ZY&#u@IX1XtTfL/+1C4W@A(#a]B.*6koX.e5i,3\"\n    \":Si(ah&3E*.uM_&7@#J?]dx+]h>+W*;Q1=(&KQG?(WSYM.[LI#q5Y/M>.Pqu;:>tu3fw?Mh8RtLLGdc2XSaoRDOm,3-EjK3&5p_>#7P=.]_l1YXf10]Om21DJX<GM#h3G>x*];k6e9di\"\n    \"ax7@'^s_*kwFR'j[Yqr$g%b&#D5fZ/%jp%#p:L/#s->>#/`j'4HduA#iJ=c49Z5=4'jE.31N5<.cQ_G)RtC.3?_#V/<sQ['B]ew')T4P(XkRP/^AUv-YiWI)Y?i.3m*X-*M@[s$Nghc)\"\n    \":'`hLV.NT/x$(f)<T9W-/JcZIGVOjLbf<mJZs9^#%D$RE4]^F*w*D.3[_BN0]M%d)H1i?#ax;9/IMrlGHU<B5%H5#$KN^N0^A^AVJRc<6+*51)s)-RM5O[=-'C/;8&)kkUe@[eU=Lrj#\"\n    \".Vw_u<xip&KR$'?P[62(bSMk'p9a^6WL>#/hcL(&Jp'&=wAUi-:])+5oKsP,Lx;J>U+Ld6`]RR=i#]1%-iw60o`8x.DXIh6Z=L6A(KamF^.VR$w8Hw)dT**5>N.]%peI8%kpH[B5G_W$\"\n    \".Y]O.6mnDXEK0b*D3hUB6P3fUmngoW%<iY#2xmn(D3gW$_lL(,@Y(Z#43f&,DA7i1.l##H[LrZ#Z2P8%LTR6UM?tV7`0^n&`x-g4j*Gi:_Fjv'W4hk<S#L_('5YNFp)wTBt5Ki9,``#A\"\n    \"K#P=u_s_B5+k3D<fk-L*m>g%#`H`,#.->>#u)=g&U$1EunVl]#FNHpSo<Tu.(xkj1>SUZ-0%ugLGtZC#$`^F*q%K+*J9v`4.QYx6jB@X-n8jQfUAV6Wd45cRTB9m$bO3>7On4V/*(PKf\"\n    \"#thR*U*;s6M-(V%Gkhg2=&O+-,8P$,mT+fUaYa`$+hxJ1=oaw$)q]/1km5,)90r`$*k4g1P@Q=#4sTB^.daeoNY5T953.4:P:I.QY+EK;Zvnl6KqR[#`,7j'<Xm%dvsel6L$+X$T06B$\"\n    \"/M+<6_xCVtW+f+MF=6##*O)[$_7[0#&2<)#FcM%ASt]:/R.J%'(%x[-LrSfLq9j?#A;[/1u3YD#<)]L(75^+4E$bN0'_KO'/dtHV^whaM%GEO'b*4ImZ4)qMjmJc21+KU)s&G$Gtv(9.\"\n    \"qd9J(5F:B#wr0ntYY*30319h(-qKJ:itj34jtIw#K#xq.26g3Gx,g'&]22K1Yr@/Lq+fr6/HViB>+$c$92I&4u4*Y$B4vr-[5MG)@$HIX@OZ<-&ZFkL0o@d)X#Y?->bPb==odZ$@)xtd\"\n    \"KdIiLrpea+Y%l,4%Ct%,a8Hu7KBw_+$#P%,KH<%,%#5`+2Zp[#<%^_ulAOmLk`F;7.s7TK.601gJX2%B@qXjN'E$8MqL3j0>PLu7W(m,41d_tml?eumW%QwHvC^v7(I^n)X7;t74a.f6\"\n    \"#j'##D7NT..Yu##555S.,PYV-&:;s%x'5U%;H^iu'j7W#k61nu(FLR#273h#V+%/u/7ElY)5-1I>x?o#8&MK$w%G>#:@E7O[305#B9t87:&>uu1rqr$qH5+#2*]-#Tst.#j`-0#-SE1#\"\n    \"DLg2#]9v3#oji4#&9J5#<8u6#N]U7#bUw8#>*'u$Xo&f)LI#<.>AIv$J[G<.*W8f37K6C#_DuD4%8?1M@9MhLaP&J3oncD4SmfG38`/v.]pOA#*NTe$n`e;.5er=-?j>116TID*C#*w$\"\n    \"dhlG*)Qf]%_^<c4VR:a4?ee@#:-lA#=pdC#-SK+**14D#F9@+4f+4I)kNm,2><<P(lJ?C#DX=V/w=@Z$ZUVZ#0-GX$v=JD*8k@5/5;H5/5*-&4p0h/)lh&E##[e#5(qHD*&'<A+w-C&+\"\n    \"sQrV-dt`Zu?+wO(jx/C+xtw%bxs$5f*r9J)5X:5g%UdC+(Y&>(N_DYP3Q_V%[Bc=-hW)(+#UPcM[+?iuI>kq(QK.H#R&pV$N3_?`@OgxX`)vn#E,vG(WRxP#AZE[,dg*ci@0h;(e-MG#\"\n    \";xV=G)'2cu((7h(KXo`uGOYXW.*[S%2$[N#f+1S$eP]v#<(oRR&@BU#,_tAue;Nrmt#to.E%_>#u*Zn$wEGF#fgSXW43s@$;/Z$0NHluYN=4Z#2CU>$&0pp%MvQ#5O=3E**2OI)#a-V%\"\n    \".'`C$i<kp%W2Jv,`l.N1,WF;$XHs?#dKNa*1tn0#O/4d*$a5iTi+N4'FaHO$dP<T#3o(@(O6=p%u8T1TF:SucJg;i%Zi9OdL8T=>mAIK<A^(ZulO'VQvfd_uc#(hL-E&&]RvBSIN7nGX\"\n    \"#+Og%_0eY#H8kp[;12Zuqh[Y5KDtYu2*-p#sEi+1SHb@bIiT?PgE`F1UfKu#YLhc)CiP>#J9GYud31R#5;Q7n9.3rm])X7m3PD@&84r?#8_pQ=(/5##(S_V$T6###Kqn%#I#fF4$&QN)\"\n    \"DuDT/MD,d$24^L(8ghn^;JmV#gKF0uW&mN$i[Sm1W(?X7B/E;?#]`fCNl_6a?\\?<p]>7%:8QaMc)?C%##AEpD6]dUV$Ua($#U-4&#M,>>#P7H5/nsFU.NJS)*EOI6/^c>>#5aAgM_6<d$\"\n    \"(Ro8%APfx$?U9AX]N%8.(?4T#R;0G#+9Wau'^OrF1@Wf#pa11HE1^iB5g9%kAYS8DgG11[`>$J#J4kb<MNp$JUL[@bPqQT#trP(8YBU@b@%H$@8pdY5lj$/Cbhs`@@hr77vpuH)W^>M*\"\n    \"V%*IF4;F)9(vrW%uVA=#e&U'#[U4G/Px;9/HUP,M1ZBj09x;]-+'&J37q@.*1+cR*4`8a#f_.u-+vk/M$Fo8%TbS['fI#KC4f:HdF3*dRgT7DLwpv2lUnvfTURkY#ePRBfYD-Pch_M2l\"\n    \"%xfpDs%+&eBKZ00ht>CgY:]gGA)7.T^MfSIgx+>@6ctG5`#J6Ej^xO5_:nC<48c*uK@n<.u@xA#,=n33I@NG8ZZL##(AP##&R9f%JUcGG]=dV@3C`_>6uG'Z.Pkd=(jPA#rC>Z,$r&r,\"\n    \"rob[,$Yk]uJ5ALC8%0I$1Y=R*@KCW-D,2ZX,)x'pbNIdVwq`R1LZ_-SIQVENUHd%k4Fqf)^>Eb72=h-M53ULp#YkA#%O,W-ZKX_&=9Y_&b&Pe$R#]RXnGhLHe?*T/1mSp^4mJ4SEQCGj\"\n    \"J.HP/bVw77/GY##0+no%A9GJ(QDw%+sIdCFS/AZ5D>N)#ToA*#eI5+#u$),#/Ur,#A<x-#Smk.#dG_/#txQ0#2`W1#B:K2#Rk>3#I*b9#gbtM(,Z&KMPX3]-.nE:.W86/$F>`:%@iP8.\"\n    \",F^:%(MbA#lHuY-d]m--p-h_4n=EH*9EsI3*pP/$OBW)+=;_j0X&l]#CDXI)^]?<.LIEW-xg)I-*^DD3aiaF3]ei8.[:.s$m;8Xus`BQt0lPj#1W:;=IVPS.?Rxt'=5T;-H4r5/S9rkD\"\n    \"Ax<sLFpZ5N=4Y48tZhwGXwUJ#K_U&O]PKI_C_s0QFIMB<*qx]%pXC%OB6l^LjBVmuOm+s8XUp=BME]S8emb(5swcL<lNwg)KvTw#rV`s%*]g+*dPf+4Eaa@tcGxP#X:bfU]T[Cj9tRld\"\n    \"5t%,Hl2`P/%'R[-N(ew-7Qb6'bYLv-UJ#:A%A_0M.qr52I)+2gNc58.<q1(HX8=#HwwFl=JMj;.;CFeZ&`w1K)XSW$(Ane2u9_9&^Xxi1fLWP&k)Lu$6%OD#C4.w#L5EE*(4n0#T,###\"\n    \"I]p##hb;8%^$EM0nhO9IV+fA,+eDP%^UXPA6o?wUOlL+V$[J3lr01Q1bQw<7@6s7[/)Ffq@3s7[oaM`N+xhiUlFG'Gpj@#5FLm<7-.7m8oUmfV$e&gLjS6##S]iW%.:W'MSYW,#xZE)<\"\n    \"c9Tv-0h%TAu5<v6FwxZ$#5U8.T>%&4dHkL:n4aw$oNv)4L29f3G.,Q'-.2t-uBQcM;v8S4ohH;$YXb'VU2HgG3IK`InOZmb&YWQieF@&,5@C=6Rhc-LiYiL#[BiVh`ew6NeO?nM4G*/D\"\n    \"#`bM(@,CJETsZj'=aGY[D1JV$;jgge@JJBg`l8pM_VEg4x9.w_xO_>,r:0b*<(RFHOC8T#iW-lX*/SYJ8AM'/a8h*<x9(0/CD&l'3HHQ:vI:B,6;G##Ta]*%S3###bKb&#P0;,#(`[:/\"\n    \"vL9k.9`p>,p41L04(XD#?S<+348aKcf''u$+dfF4<BPF%3#4I)Sf+Z,UpB:%&Q'o8w>Nv6Zc1&=qk3^,/[l3+8dVI/nb^d3`Et7/-okAua.97;JYHAF*^5<eE['1pH/3a*e8o*.c^DA+\"\n    \"1WU^#1RM%7'=_'+HF[8%IF2T+uD'A9im-Aul8RK1;e2>#3J75Jjfd7&hRr<1C]8P'L$Fv#c@76/x0?,*MaNjLYFPO/Y3=&#vZ=oLb$^:/gEPJ()=Zv$H/XjLt6LF*N/ob4JUh3/-4Yd3\"\n    \"nqR*I&)]b3^c,##FJ1I$9nJ>_8.VtQ;s7iLgIu_jO>9e?X'1,)8^;v-,T&BXUiD<%#,>>#]u@/L*VUV$8Ujl&G^CG)I@$##d%lV-2vDs%7;LZ-v$TfLti8TAe+A#.%E6C#p9%J3Mw:q#\"\n    \"h,'U#jJVGuj5jouV3v7$h^FU%0+k[bFCkou/(1J#]f#ru$KiG#o@>/(WaH[5-0&6(`.s.L0%9/LEs]=u#X^2uRx7/L$)wILNT+2T>(Ld2`]sduvdHO(HSNI)h2h-2Qj;A+&,###ZY9)j\"\n    \"sb:J:[=*GV_)dA4'r@8%$;Ls-JS%L$Wrv#'XqZ1Mao^;-@X/KN<Hgw#kK(E#i'4]-Z0fX->I1F*Ll_v#?VX1V&Xic)PYi=.l((=%(BW1)OnAf=&xE_=GN_mSkW>mT^TUItNeEnL;,;]7\"\n    \"96`[,VX0##N=n2Ln<SL(#ame6^xkB#;4wK##O0>#jHOwTBhLhL*KKGM1P8Y-Yik-6aak4)uP2E#HpKG+PSND#Qbr0#]5?q5.sg[u,G5()eU*I-'3j>$sfXkLF1$##(?&W6Yu^##-l68%\"\n    \"2oZrHW@T/)h-1,)Z.65/aGUv-]:He4gpo8%p&PA#?,7E3']0v5x42#$1kVW%&,]]4dWZdF7Gn]4.-w)4kPu-$ox>H3)'SF4Dwl05<DXI)%^$E3MLvY#Oe+9LUVhT219YY#wlMV9Yw5;%\"\n    \"+YD>&[LVS%TclY#BLnW$_MRh(DoNj1XHpQ&QBT6&@R#6'i#?R&D@7w#0m0QAv=e(Wn%fOSUp9?,21Dx?*O*Abq>lZ.O.[cElW:21iugQ(09H^+:j.^?ux?`acckILgX_5L^9*Z#B%mY#\"\n    \"DlL;$H:R8%W>)W%aHB:%P)E&+EXZ(+0Hu=$N&.H)fRb)<VCw8%%Gn_W+MB(JvDcOFg:pk7V*pn/RS:w6A_bv6ARF?QRJu(5#>5FlIwa0Q&,###0Lsp%skUf:Al,AF:E-)*3`jj1Rg;E4\"\n    \"OW=*EtrnP'b3Za3B4vr-DrU%6w+m]#PY?<.6iZx6+.;t-SiY1MSjW@,j^Aj03),J*vE')3)pCv-f8t1)?;Rv$s`UB#*5@:(iIj1'cdl?D$jXn&j#6tA&1p[uIbdT%:VAO;Wteg7NgAE+\"\n    \"1dpwB7BpuGF%F8/kB`d*G&KO9)=+MC[-DV]:#%/Q/#E6H[g8uc(g@L(AghKMxVG/L@hh3?0-[C#sVgtNg4o;mBRr(:Fdi(M/WQG,OI8M1h(^:/N0.,*[1RG*9NSeGdMH24O3JJ70+lTu\"\n    \"?=g+-#Eic):r9%tgr`cGs7w(#&,###Su@/L>Rx%4u$fu>XIpJ),5*j1x-@x6S+h.*^tn8%Zi=Z,EKU&$_'oP/sMYx6]81#$PVjPJN:T;._R3<->LJv$b/D/LbP6tu^84gJD.Mv9sB&W$\"\n    \"L4irA?Us?#;FspLOjr$Me%[>#IX`rAFZqY$`rGl9Qa*au$x3V7du5>#iX.H+vN#D#/CYtAidj9Mkm8b6Y-bPCo']I4uJKt:5[n:&(2S1(u;K;.2=`[,wBS<$&@)`+&R<nLv$J9.PDQD<\"\n    \"8Ht7/GRc8/oRsH?a(T/;HCVq;vl^Y#?]H2L7KH:6(Y+87ESXV-B4r?#tc(T/=V_Z-3]Mc+wPCD3;v,0)fvLG)rZvmscFn8%_D6C#U%`v#x/V]$9ap]#YiVD3q.Q##e/c5&eB7rQ$tW?u\"\n    \"uG%@#(h?Z$PeRs-wfQv$WLT[#@fc:Q&gg/)L<:0cEuQw-JNPr?SGf473G(].3B$VLC-ku#51rv#5dex(>Z7d#gQS@#_69R)mHJ@#HT+B#0R)6kOCiV$J$Mc#qGD`+XjZnTaq9.1JY@W.\"\n    \"&s_ds%2PuutLC;$d;V$#YDpkL*^/%#X-xZTg)Cm/(_Aj0TAOZ6<hdf=DcMh1FPYx6A3(A$jEa$#tNj-$v-[guw5_&fm%EO'_n?eM:vN;rGuM^O6nNP#Nxu=#<x<j0TnLuPoA[quFRK=u\"\n    \"gp;C&l$P/(+e@kT2*J#(^tfOomv8iu5ABu@-s(T/#/nQWMR(f)B`Wg1dCXI).A<j1DH:a#ct-c*9v>dMI%-/()]v7/08F^uq@3sTUi8*U7.#H2W@'O#U8Ai'SI2?uT5LJ#oRVE/LfI/L\"\n    \"rL#JC[Imv$b0HHe$hX0MN6fK#8/'_-IfEFeq3n0#[)###Ro7/LgJIV6iH%##b:Xe)SaHd)HLc+3_vq%4rRx:/7GU%66T&],&hJr8B9d;%6QCH/R5t(]Z(@_M]s@QMdTWZ52/`0]Ju_#%\"\n    \"L`(k)Z0e*p56-?,5Utt$9+<7O0TtxbS?HvX'[Mt*F#@MMVjdn*FlmtX7$=tAjW9J)R'b6Ejl0q[Ylf[g>3[Cs4DQs-2%AnL+]fF4(Q@dF8[kD#lb3nk-rdY#scR]4V?9r.oNv)4SS=?$\"\n    \"Dbi?#o$=G%5Nllka8I*Ma%>;-E+UR?cxm['D&44O[Kwxk.*AE+$rCp.u#X-vWGF2liwoP#H%0T#ahQ683eLO':=;7jR/5##)]$s$T6###c?x=^TC)'#@n>V/iQ+,2=C587ZW^^-;a*P(\"\n    \"^v:s%5&JD*_6Z=?e>cD4@vU2'845B$N$2quknhOC+aCH2KhHdDHGqT7tb^B#v][h(x>ge>A%[v?90brQ_[3E4`Idi9Itk64P;[S%'9)8&g@-:Mf36e%?Zh2NO2H-5QDx89n'%##uJ]9v\"\n    \":Uws$nuv(#W=#+#*b.-#<hw[#fO:2)B3us8Y'g(#3:_C4Qo>>#Av)w$JKnb4?D,c49ZY&#EnOJ(?Y-U;OAgkLK]Uv-jCXI)E.ZYu;[iNSOmXW-*N?HFtwgN(=aTJfmCG/f1gfRRfusma\"\n    \"3oT^Tb+gmu'fCZ#@r_DIS6jP_$WN@tJGb7/[AYjukPJn8M1`CA9gNv539m0)4H$p)]c<Tu43V`Ei=AoRM:h+Xsi*P5vZtM0R(H;$5w7r'e7pl8a50D54Hj=XaG:;$[ON4o[u^##euP`<\"\n    \"CfK`Emwfk0O1[s$TL-T.^]n]4uhd;-VgS(%d`l<-)]K%%1s_`3oghc)8=tD#4`^F*^RS(#WF;8.#C')3^T^:/4DXI)IKOA#6&(x&RLe/*AO;-_1[mb8M9;p<L&hhlV-hn?_%I,t9Ms:6\"\n    \"iecVMZ7->#'tf'M*1bILV3`>#fB5+k^sT@tLx.R#37;X-RM)=(A&WZ8Q$YUAHBKmu2-X+jIhvNWAV)Co92s2MjD1dOup4XA[to+):HRX)Z:twX0Hh'Ys)]],[HOv.'RS@t/+@8%?HDX-\"\n    \"xmBX(X>cuuqqZS%)5###i[P+#)9j$8tDvS/Y#*K,*Vv8.+jE.3D]Y58$7U'#CqC.3s=9_4&Z^88(Qt2(reJ/LNNYN0:3T=-Z6Ppk$>o@9>..nTvbK(+xA;6l>iaid'YMp.O0P<LHVWBf\"\n    \"lWsWTRLOV_tjVsJTn6n82PfTAF69mu/Q2pJ$EIW]0RjK_OLs<`s2tu-)<Lgu'cIRntka/1wtGuPRUHcXqZ)P5:lUa%-73dXb:Us&o3DP8w3a<-oDmW%$c%_6F0BiDLT^Z-TekD#^',o9\"\n    \"$(=NhElXg12Ka#PkLV:'p%huM3r;]hWl;;.UIFB+gYOs%QqpWALr2CZ8EC>Zh'an)VBAtuJmS*%]%*)#f,>>#cVWI))fjj1/whj(d?Y4:.,`*4,VW/2i_Z=7Vb7%-PXw9%'PMT.Uj,/(\"\n    \"5Zq]4+xOU#$jF+ilCDuOZ=99r%U<h(@SFe@rZ=vdHVJtdJBkV@0Pj(t/q:E3e$W[ubUqkun.nk'j)jwTJY]A(A=.W-3+MR36L1.)1?9_-xrO'fhV^-4YUQuure68%e6fRN,DC:%QpBE9\"\n    \"0Qdv$7J-W.Y,1T.d&A+4m&T(%K9S,XLZ3r7P9/=%au%[u+5dr%t](K_H)5LGXY/TW)@'N_<>9kLW`4o7M#8^#%+3q-E`sn*Gv%_$&U1qu,aSM0ge:dMA>1wM?.LLpNA2R/Xu^##Y+pu,\"\n    \"VZ9g:leC*4:vq%4uY2)3<hU$%#6]guS6k6W6u(_QOh7S%LP0C-CudIUdDDO'M@r@#m+<kMjTcReLl4'#VWsH$-<4gLO&co78pHwBPi?T.#SD;$eAhh$1QLGNA>69.+ZtN#EBXW-e?Wk)\"\n    \"7r/gLcK$##Tx^##x@PS.25f&4Vf*F3<N8f3N>g+4?;Rv$$cGg)m<W78lO8]$V+<.31[K,dEZgq8.h[lNV),SunIPX6SfQ=.tjc,3K&xlRe#/Pfa-2/Z?PN;3pv?A.GjFREliqr$pB,+#\"\n    \"Ql>x6:eX@$qYVO'<]d8/nNGj'IlOjLW;K_401$gL+,Ad)^^D.3$F7f3m:n>Pk?`[,Tg'u$ikkj1M6vHZFu5O#VE:E=GVcw8JSRT.7)dO0<9Cq%jXlA%9i%`6Z:'^7)xCj2-WMk[Ns,@+\"\n    \"8@6,*bNYI<i-muYFlDVD'Z2cVi6A]LfBHV/q+<t0K[u[$FN`V@-W1d,^&J%RECgGt&Fj13l+$pDl`[nuhorE=N.q#,7ncB=MqVBfU5>##N<&*%YZ<1#7DW)#+Mit-Z3rhLg46N'$%$xL\"\n    \"/of+4O2'J3f[Y4H$J4$gTWa*.B`w<(mNBR)-7YI)9Ko.*pcI)*M@.s$ARgY%AR/7/*l0C4bwc@YKvq0(*iNiMU-.7:1]6h*eZg:%UtET%mEEs-awwv&,rIuK)[X9C7%[+M<>fYI&Bh-.\"\n    \"o:JD*T2:)ejfVmb`0WjN*e7p#g;UW$K@&U/VmCwQ_hn]%09?x#7TNbN=vw<&g64[79.eYuk@emLFo<EeicKODV*`$9rM*puYYmAAHJ[D]m)>e?Numo%au/'#Zr@/LYsf*%#R(,)b[18.\"\n    \"vsai0R[$##'G3]-.-B;Hh67`&3KkBI*t@X-jj8.$wiK##QWs-$TF:&54HNf<xqR%'9uNh#Yf*+M8vL5/P3w.LiW+<MTU9A$Ii5<-[F<>.#1O]u<X1^#durS@xWE-Zm<T9V#TpW_RO13(\"\n    \"JDJ1(8&B.*[*'u$uaFN9t)'Z-Ql(e$tsLG)MB7g)fNqv-F.@x6jY]-bGYAW6.m@d)Gp#]b&Zvr6Hb/E#bj*.)8?7=)gbO-)R7n$'*j?QMWN=AupKpC#wEC-uxBmG%*C+S9BYGI)Tu4dS\"\n    \"t'.IM.ZnL;lg)C8@N(]b;Dxf6.>kBuSK%Up9)n24m<$[A2+;X6/<0N(11&lLpT?##UjxE%L*_4.7a2JO[NL+*]nr?#HXX/2`,^e$v#h;7*8_e$9jE.3TruLMK8-9/<=[s$C^eiLnopcN\"\n    \"d/S=-V.<H*[YWI).v'd1:Hsp%%clN')DQ4&v`(C&N/TY(iY(4^+FSl)7D(h0NW#UT.b7A,]u>dNhb-xk8_3_A1th5^.UKu.UOw0uRdLW(>`H[-V+KfLQh$##0AP##OD<A+G:$##8&B.*\"\n    \"T=].%/PJv>B`kA#M4B0%ejS@#YQfU+DQj@tI(65/SEt7/&AY>h*m:n$rwnB/JN3@VKb4R*0Y8E#>h_>$nvm8/UHlDMPf$ju)#6X1%<AbA<6P#%)5###Re[%#ZZTD3,1;W-dq;?#m@wS/\"\n    \"ZhF%$)N_$'8gZv$N=Snu>gEJ:x#T.UI)aPCNEp_u?OoR#inJE#6a/auob#4%#o0gaxx3%b']Ps-fKP+MC_8+Mhk0A=7Ls9D(,pu,2SBqDX;/d)Unn8%$rh8.wS0<73>%&4kg-H3',Bf3\"\n    \"0d%H)U4Do%X;jP_1*31^/(b**&6Q1(eo?pt+f:BqEn$SV=b&]tf'Y+`Sf5tLf)@)(Mp%tdg%q-$5JbTtUfB8/[hMlfQcR+Mi2$##[wDdMA9V'#6hiH-O9iH-%(Wx0G>(?AH:[S7Y,FYu\"\n    \"+u'B#dIGIS=fB(MRo.QMV&pBS.)e%'m3hA#V<6),d%mxkS_$##$QR12.1Fs%bDL:%iL0+*5hUhLuiYA#qc4c4K30@#9Y&>(id#V/)x^M#<D`G#x%9cJAUSM'hmA(KZgq=2TKLD*Gq4iV\"\n    \"%cw7nXMxWZJ+.[#]D#^&;Gc>#G>5I$GjLWH1^Y#'It46u%U4Iu9hCZ#:H,V+8vtX-EiG*R8]li9Vm.T&R*6r@gB'Z-:^c)6Nl^=#-8bR'S]mRt)5###6Dt[t4;Rs?R5QlJmm5Q8Ai8*#\"\n    \"os4Y#=F7@#fd9B#<>WD#ghlF#CabI#M]4Q#iB9U#a+Pu#3PUV$?1[s$xg;E4V#vX$`a&],:@i?#[P[]4?&?g)vSC_&fA9F.1I@1MFT()38R`l%J)TF4/]NT/5=Yj1lk8a#YH-)*lU9+*\"\n    \"s)wS/Tcq@-9RGw.CKWa4Rp#f$P#JekAIB(4Xq.>-fj,P0[]8)*Eh_F*gw)mL_,<9/9WRl1(N^D4t7IH*p`[D*/N%I6&n/I$:^Rl1t%2B#/.aa4,+H87;'UfL@B:u$.aJ<%K@[s$wqSfL\"\n    \"cc6lL7xSfLW,f/M2Ci8.`20X:T),J*r3Ye$'8^F*G@q-MB%NT/./:1Mb0WY0$g(T/e2ob4]L#gLpVI'MdaDE-MlP<-w1i&Mjtgx$oFSx$-rxfLnHPA#i,&Z2al@d)a&SF4a*J5/&Y])*\"\n    \"TZT408]sD#VeTx$.saHZ4(ro.IMQ,*:lbk1MQT:%5M]C49>1<7F/ahLtA&$M;FNT/cDZv$cIR8%EE*jL+RcGMOxMT/OEV#$7,$C/%Ij?#7qfG*K&(RNlR.K),*ihLGEo8%(QK,.<Za/M\"\n    \"8>ClLGx3+37N/R.x^[+4)]9T/)GPjLpQ,@.8:8C#MVk;%7k'`04R%6/0l<`#jUBiLH9dt3t3v_+Ye#&4I`.60gTUK2DG]w-,35;'i7Fk:1Guj1ZZ?+GN=2+GI_]:/dabu-6mTnBt+?`F\"\n    \"k.?c#8E9:%6#rN4kM(@uN:AY*iZj4`>HU,)XG%P'Y'KQ&2PA5'>6&E+[6F9%pl)q%69vb#7mUY$psJw#c=S9&GB/o8E0$/,q#v/(m70&$3+[8%ONQL2'&%927E45Ob[*]-nB^]=M1WE6\"\n    \"Mo`V$2MlY##ZOJ*EBId)a4xF6LZrK(c6<?#q'l6'7;qv-6cDq%p9</4IHLG)9B]&,.UiD+[tWT%c$J[u=?>c,s'CJ)#pb)+InB5'AK7J3S6_P'.59+*`i1Cai&OW-@/Zo/UwC'+XfnE3\"\n    \"xM:g_N8PU.^6*D+n$BK(GjhK(;2f`*=wfYX:`%S4TQC8%@H[--4GPYu%uU;$U)T;$]U$t-QJG?(QxAh(8@[W$S$4p.g:DCX,w[kT[-cJ(r=Y%5)oi;$<..s$GtjT%R'==$,U:m&pdX]#\"\n    \"333P]Mnc12ug:K(/5HA#xOMn8E@xG?Y0,O4&FdE*i6AcBG>$E*Y#hm&nh@@#;J.@>KRGJCn'_h<`[@Z7rSN>#9M/a*H()v#$xtQ'^s>/(wn>mc8*Y;?1N)69BsLZ>El5kOidXp%R6E78\"\n    \"uv.i)uW&W$Rf#(++-i5KOp0W$X^_;.@fQd+@>.3'Xw]*F1W@D$x>>sDVFDF*j,Ba+BJ-*j=`<B6^V%*F%p/w,JQ$DGG44,2S#d40IaciTi@iw,W>w)*qa06&qec?,XsTY$1tnK:Tl9-4\"\n    \")F0^-']''+Oenw#.Ml>#`A6$$PfbV-e.j.5SJ(F*lSn1(Z3gM't%;>$(A,,4;XYj'IUIw#BD8=>#&xw#gD)O'wLxL(*Cl(G4^1^#^MvZ$p-0_-Tr_3=Ur2V%eQN;7EXxR9x)oe*B1@W$\"\n    \"q%p#,[N9q%'@qf)PRrP,;.L$/(i==$.(`h5mVvN'==Pk't=ixJx)uq23xr@,jR:@,WWjP'i>Iw$=PE$8bkZjFIt@@#h/hP/Q8jh(uTq-M<,x+MXp/2X]<GfuN>P>#u09N'%7;/:(5S;?\"\n    \"=))v#8=C`$8K056m+fs$L,'N,wVZ4'5-Ti2LU/e)0>cY#ZlxV0)[4T%os+T%_1ffL,jOI#ern-)4AP>#aGWv%trQ3'o-s;$afZ['Q%.^&[1[L4W3oY#_3])59:teN>#VZ#O>w-)^KpQ&\"\n    \"TO%seh?>s2c=;v#gh65LwKj:8dE]c;<I^q%fE4=$HlH)a*b2P40qhQ&T,4O'q7:X3w5>##pa-w%=Q17#9(V$#-jKS.T6mH2S^Bm&ROr_,?IR8%t05^$7o7T%i:0=%[l`jNmo6Lu681%B\"\n    \"e9d7@.n.4O2MXP/m%EtOs#eT1Yu%hEbPw^C^-TvA@TLE<m@S5YDGk$aL,xs8xUC0MEf-mLKpt6BDFh]?6*XH*W>EE*H9u4:2-<%8n,K@H5k3i<m_G2(VC:[,f<b'6U^[+#W:4gL%F#W-\"\n    \"YP&eZB[ai0X2t+;W9x7I]-L?-?'>/(pIY;-detX%[`c;-<DOm$ZH&i)ulqB#kUFb3M$A.*Ynn8%#5w20g<7f3[>2g(Jb>e6s_M/)$o%p%(gB.*lf/+*s<RF4gc[:/_FUcDQHm[-dQO20\"\n    \"Gg6oeA^8kkVV:A=:(n'&bf'J##nY6qjUsrT>c;;(tui0(Uh:7;.gDO'Kl1@,;-h(WmQ]v*bF.<-^m7u-jm/UM&.#pu2a$mA6>aILNgAE+(oCp.Mf:kk@mx4FL:LxBlE4OM`FoC<wV4RE\"\n    \"2m4U7VN8^5rs:h(rAUV(d=X%$1/P(._;VfLZC$ipJ.e8.:f^'AkMWvQL49uPsRvHHvg]e$:uq+;1QMs%`Dl'&@hx+25nOJ(4*CD3Mp.<&84xC#rkh8.8o=$%4NZ,24q@.*%aHIL+XK<L\"\n    \"RD_$bYt_;%/hvC#WB[:AbBYI8)d=?%9Wu/4qv]=u1)JAuh?E-?h2f%uZ(%k((>)kup0'OVEtC#$@nRJVff:2P%L9cNw*B.*pve*.86&;QVM/@#Bj.^#h7MrMx?H#$^nG^#HLv_P%9X1B\"\n    \"w6qA#gt.)/UiK##t@J&Q&B6##'7WM:tlIfLS$w##?H?D*+t[.4Ss2R'BhE=-oAJI-+BKe.$h.##x11V$a6###@,>>#jCh8.tm9u$`Ld5/Ti$s$ax;9/*-+c4+g^I*pleM(57T+M#@gb*\"\n    \")KYU&i2NA)(O&n/)/p^+Bwls,@4Vo.'$@/;;OlA#Yo#50i+*[$D8GX$r^HwBYA(v#T6###I,>>#GA*F3+S4I)J=[20<=2W-$o[@-F?Ke$d:ZLMGO^C4N,k%$N0FCL%B7Z7olG<Goe-n7\"\n    \"%/Z5L;C'%M8xH$G:v,U73=uqu83L=lTB3,RQLN;-uA1XMm@t_$Ae>ftm&'%#Uqn%#n&U'#4pm(#xCDmLQV1N(iRG)4LS)W-6Q,F%Mc.Z$S_x<(pA+P(aZ'r.ElP0P3H6qV=jlX$,xkA#\"\n    \"GW'W$$YbA#ES2h),XK<LI>k=#rj9qV&pT##OS9>#40AU)$bj-$w&PF%/G]q))rdgu%#@KuNt?KuR3>uuQK&I$]&=44J8>>#jach#ncn+M%4pfLw0YCNS@$>#'5>##N`9##@M=U2WFQ9&\"\n    \"#&5>#2GY##:Ba(-0%J(#Pc/*#O,8GP/-:4.DN`hLAw9S-esvl._:8u..h6T-[K-T-CYlS.@.Y)4V4Av$1tc05hS%_omqdgufHj<qu9wK#o)>qrpPr.L)EGO-%G5s-%SjfLsbA+MKC6##\"\n    \"1%g*%VHM#$#-.#N:#7A-lwQ2MH*oJMPjL<L/1TgLv'^fLr[jIL).vW-_S$@'EWk_/=:n(<gO'N(XC+wpiDDa<&RMx-hfHv$@4n8%/#N1B93dr/t%0'5.kaj01L-w'=dRF=N:b1BrCr&5\"\n    \"6[4-5T6;U)UP###aU?%&]hfi'xm9e?cIKC4jfRu./p,T.JgQJ(27d`H8x]G3TQa]$i-%p&0);+r@og=#5V@D#>s]1_pt[&uH-7E.'VZO&9hRNUM;k=#Op.'5eaQk+JFDb.woEUMKCY'#\"\n    \")&>uu]mUV$1TXgLI=2'#dtu+#2$###PD)c<`;YD4GAv,*-tuJ(*vC]0O3ng)c?XA#vk-lL49[d3Hi^F*b^,,2ZQ/[#9&e]4.%^:/jBuD#XYPs-gV4jL6RP_(rvK,VlH'6&ix]T%'%QG*\"\n    \"Ix0lOIpHD*esV`;,$m24UQiB#Fm-)C?EvAJ3^qQ2CIMlK@:e31x2kWC^[8>81)j=8<rPYu>N]);(;hTT_i0h3.o2Z#gx?8['Vd>#5*mxk$H2oeRY&)GDcG>#FGj=%U$/bB+b0(GBolY#\"\n    \"W81uAq=?u/GqBP4#8nS%dOs:8(5cu#iKFf*eJP<-CqbW%e@NP&lg]f1b3%##D_i?#I,=jLDU0N(l@@[#EO=j1KJ=l(mOd>#ULD8.m_)Z#cE4=$=;-x6)eIk9;@h)3p]HRM;$RQMTL18@\"\n    \"RxXEVp[M*A&0i?#s7.[#[`1?r*Vcj[ZQ8/[SppP#+FnH_Yi&j*D^YQ/X`t1^^;>&aO?I60@[aB#a]hnui:1E5kU?O#lUijuBm.[XQEF+ie9$`juS?(p2uXCf;uUJ:92R#6qwL/:?fK/)\"\n    \"/b$B#=tjlaIw1x5nWx)vD-L/LUS$%bdD24'24K-)@X-dt8w%?AA]n;84L.nNKI,XV?1&pA0/973u,q-O(&BH#&oq<MghWnLPo&?.2Zqr$&9/W%[%^,2*AP##@>N)#;aX.#NoXV-xb0B#\"\n    \"J?1K(--w8@i;BZ-5kRP/NDHT.Uq@.*Qb?d*RK$<-ED9c$J.@x6q(b.3bn%W$Ew)w$gDa-$wdP9Maik1^E:s^#a^[h(q>B@M[[klAB0OZuCUnm/24UOBn)V@#2+,t6'r'32s*>@$3t(GR\"\n    \"'.n(AS/oQDBrln(gk(eGNLw7RPOlS7$hJ`a:*1/LmvUDt$IqT7v22I$,cXgLMD`9.$UfE559O2(j8,22cPbT:r2)Z-.I@X&H$j#`t7e;%H+%9Prswn8VPO&#-7ni0HdSc;4e4/(T`*i(\"\n    \".Av;-_Xxv$Am6/(?l`^#_#aI&.6MG)6oor6;?rJ)#o$],AdS=%k*eX-Yq[P/hHeF4uRh^VC2*3)*[8N-<D2X-/YrNb(pCr;kdn)unn5GQ]cgF*<uY<-<90k0N,4xtg_04E7Q3xtuUgB#\"\n    \"%P:8EwEgM#J;DI2O]WlK's:UMfDnK,?MhZ-qxZ?>,a3N1@L,87[=vm0q$LF*e#W-MkF4jLTioB2`qvo%c:cm8TbN$n]1hx8^J/:82u(l8rJL&L=l#']AdKY>,OW9`Eav>`'K6C#'@j?#\"\n    \"_LX'1'5;G>]fD?D`@gT4*D89f>YGi'$SuQ0b(<K<FV)$[uGrU'u4:W-c?&.4BY,f#=Oa:)kQQ4c:j1R/WhgS3?MhZ-#4'k0l%*)#rPUV$4tFA#S)nD3wHeF4)33Z%c?=Q/bh*9%trN.)\"\n    \"P?eZ$6`[h(E:`2Mo0H*$vMji2-iQ81T)+[?iId_5gRV;$>-N=-e#r@-k]?3#-4Dd4%)k]7PCOa,f#tr74OrA?W1g=R^UZ##'b)kbGd`&4eUs)#9->>#jBFA#+U^:/.m@d)>Ydb%ejgH*\"\n    \"dCXI)kHL,3+DXn-KKTe$uu+gLnXMaOWE--3+jE.3<o:p.]3B:%6V14)s975/)1Nk+G=tD#%EZp/Q_S1;7Qik1pXN/1Ox3V/;Y&/L/NOaE?nI:.>?Cq%Qnh)3Nw+T%4@0;8Yu:a+Aj-A'\"\n    \"WXJl<cuIiEtT0FPGDIs$qs8l1;0T9;g4;Q2+Ps^up-/>MmUqC2EFUh/tY29/NVmW.&:x50g)uU%l5,$0[G958*T?Q3Ljr.L46Ei2k523s0'Bc;+4:+Gl<pl/muN+C>RUpLj?do7q&:'#\"\n    \":j]##Urdu>Qegv-sZw9.[xU8%Lr@['%If@#kHL,3/%:C4)e[FNe%Pp7<_:E4t(4I)^Y%_Qr%MB#p/2T%JPEb3+g^I*W&4e@$SDZ@gsOW7jV-A#b+La#3g#>%`Ds9)Z)u87I39.H%h%lB\"\n    \"e9`d%Ls13=q[3,FOJ%R3OU=13>1R.)`6`B8m+_f#;<,<8cY*3fWvDo0xEBD3^)YoRR^;fq2(P]uk`hV%90At#ApA(:UWWxB08GrD.rwm0FKYOD6i6##jI2@S]-S&Cu8vlL=2-Z$NV%JL\"\n    \"Zr@/L)vq%4%$;MBQY'##?f)T/a,hf1pC,c443hZ$PWN^%eo`G<d3/=%@$,j'Hghc)^^D.3-)Vw0Qc[:/u6AW$#P&u(3U*v#Q4)=-4O@q.v0eX-Ldt?0,^f+4EX*v#7eOv6Bm;hLKDe;%\"\n    \"d(4I)o6b8.rC>Z,0g/E39%i;$>LRI7roE_$u>8@SmG.;1u)l8EJ&6;HbP4@S=B=rZN>TTW+jam1OK9A=*+QS7x.[)E/gii(XCh97'+8@#Y5kVnq7X+*KeXt.]uiIL$Us-4T1Q)2EC)S:\"\n    \".`kE4pK2oeo`DZ@H^]f3g8)^u-bar2F`NYH/vq5SgNh$,M82@S%>q8EjPdfOQl-]#59DU'AGv98xYYa<-jRfLK[`MMh@Kf)&,dX7hL+_48x$o%d`?980Sj2;`0LecFJ9-uAlTY&38w.U\"\n    \"C)#e-Z0j'2Qg9qfoJ:X%rLJ3:&;'?Ib3n##MiKS./H&##.e_F*18qW$]Vd8/$<q2:+Eu`4KblS/MrjD3;FxU/9>:Z-uiWI)B76u68B7g)A5mG*JIRQ/?DXI)B.i?#c0cB,,]WF3=s(Y$\"\n    \"(TLC&F0(A$se7`.H@?/GCQ:n<tipUum_nIYk+p_0lUTBR-`Ll<E4^GuKZ4)uRs$$$,a?E3-A3)u$9fT%`0&R1bO5'5O:&*3tnN<8oEG]#sU`?#gs58/.ltN+20mx4:wbEV.WBq<[E%x[\"\n    \">&gC-LBfQN^L6F-Itk$bO)<$L81]:/YLFj1G2:?-HO1R'?9dr/u2cR,_D;B-_U/gU?Ga@cvrgs7%MJ=%T6###u4C/#mJc8/SFu)4UA^;-tk>_$#k4A#HHJ,3q&(T.q$5^$#YjY$#2h8.\"\n    \"UBo8%%?#g1%r8k$@MrC&0TID*3QCD3Ye4D#)p6^ZaP8f3P%;iM_l$A-w3]T%jT5#<x4s<'vc?mJm+b-?ajZ_=u`@k=mJoT@(%>B&nfvw-n5'@S=:ar$jNC:/8D#%Lw]X;/qKHGM=aes6\"\n    \"iZ$'$UDwS%:K)]-(%Ew-Nhx1;NmY]u'`['$iaKU/M;]M+QW&&v$fAF#NFiO13P3u+1wbC&H`m0=u/%;ZQ$(,?-$Yj*Lc?8%2m`S&k7&(7=>5cMcAvT2J9rc#lc2:8m:)?ukb$*/**ER'\"\n    \"mB[&,$iNxF2E,A#Agcg3Q9t7m5xU?#vpGR&Bk9:/^,txF_+iq8_ZJp7^wVw?9a;MB4W&##bl@d)FjFdX[R?2&dc``3*bsO9n&/n16bWj0a[NT/4tFA#+g^I*<_$@'?o`U.Hl*F3+4.m/\"\n    \"&7X1;ZZYg3ZL*r$^SU:.*pI%5b&lV79_9B-$XU1;I2]IE<#ZjBB?VCGVw)8A.5s8(SQvC3ElV20O$H'6:v`>-Wa/.$A$C/Lw:bILOj`h3p1->#2RS@#0A_mi>?dr/lH5<8#K1g4SU<rA\"\n    \";>*J<2EYkj,0$x>?H;mi?,)VQT;x^$TuB[S+gP,E6&*L#,iA.$]=rs'+5v&#K1g*#]4n0#n#]I*?*X)4VxRji:W8x,o:gF4<)]L(*^B.*b5Hj'43,H2d,]+4bT=u->r_v#iL0+*.qL]$\"\n    \"TYDB#wCbe)x3YD#@vE?%0Vh;-JVM21sbfM':]d8/'BqB#5AsU/m>:Z-gEPJ(xAJa3FND222)fl)jXrIC%&xd(M>A4Mg^W>h/f849Ve.a4OK/e4Jn4NT5'a;**H?V%VC168G$uU%w+HT7\"\n    \"b3v`sfwn`c9-97;'*X68%W<C$gVoW&*JKY(rjM+=oRisfQ29$7ZKf$3CDu-4KUU:73_H^@=_^iEb5DVQJ1Ok1uVBp:mE3@Su@3xtx;CY.kF_H7gu-P)5W,KN+O?k(KUSCM=(JY.`bwp(\"\n    \"T?(E#b=8@u'3Qr1[@A(4B7BCu.#<q.-9Zko.EU]=o:ccu2tr69H;L88o=7dNpuZ1;7`e/15^J2^@Zv%+kN%##s8A^LYJB.*XvT:%x3vr-':N?#6+g*%+ASfLQ1<9/U1tD#bHmqn?3Ld2\"\n    \"SFR5)n&^')-aM-)pTP-)`A<&+UHpM'/c/6&*N)h(nkbh%#X'r%vUmf(#eX6&Y_.F%YE(r%mE%w#qaI1&9j2h(4Ua>'6ri^Ml.k31q5uY'O+H#u/=B6&9XIG;JK-.)+jjO]TB96&W%G+'\"\n    \">m*%t+1r8.IZq,)Z74R-#7$]%%fDM0MHKuKH4<9/>Z)F3)d4+N::.$$bmRx%;)'J3*s,l9gkP,*WpqP'Y@@[#MEG,,6r7Y.b-X=$<B?&>w')6:6ghp%@QVW)FcAw(-Z;h(kU65/DW@VB\"\n    \"Jg$K1<uaIqD?AJcb<//1mlu'&MXWSLVn(p7XCsZu.s2qu3=V0(L]Xeumn8k2]_=h(^t2wCAj*9&B)?JcFuHS<@7,bu]3lAq4AbT?*Dc'&#P^%OqXi'#?TF.#bRZ`*CA/K1r(K+*@4n8%\"\n    \"+lR_#xH^^-BEqA$[<+J*pM.)*t/Bv-iN:,VV%co793X>-+LEp7,n0H21KqPbQ/$F=B$^w#'(5Y%St*t$G$Tj:En44)@+:J)EUsP&#kxJ1PuFI#vtTRcQawT/tOx9&C]AuYK#9ZHV:C%X\"\n    \"'0DU%:WrHaro%])pZx<$OM0u&7I*t$Z0iQ;=>Wm&PeR<$9%M;$Q*_h(rdPZ-2^f'/fMut7&+lA#R5p%)(r5Z5;m8e$Nf1$#Cumo%mH3Q/nnbu%F`5J*b=4gLU-9GV$)wIL$Q:GVtHaau\"\n    \"<@I=bO&?GV$c]1B7e$C#:d()bOo8du0mpquh1Zn*hu#7*`2Kb.4A5O45nZH#nUZX/Tbd##wOd-HnC$##d$872Kx:?#L['t%iPaa4[PD<%o'Mw5Xrvi'%n`ianU;W#9&hrK6vB/1$.^u5\"\n    \",*QD*8XLB#Kaa/0]v[$R85dQ#Oak;.[sKD**k82L<3_88RAIh5[#l6<)7j6<Xb`>?NVWsSh-*$#_QI1&$N<jLc%'%#eWt&#6&*)#gnl+#uEZHd.rXkK;-#H3B3Ns@Zm;[$PDRv$a&SF4\"\n    \"p77<.KO5s.x1-d3?bRv6nEZd3j@A(##*Tv-eX_[,5I]C#<2[;%5Hrc)p-_fLS;4/M.<SX-Omd)*R:M;$+,BU/`V6C#';:8.K&.&4r=E_&/i8Y.9:*Z#3gNT/4c<9/n1Fk4.-e.<YB+SV\"\n    \"OLLA4k&Xl<L#.SV'4+1Hreq-nFYlQW1EpwL.Ug*u_>b^aoHm#K8;D4$J82igX7MrHD,O)?0'.&=AA[+M$7xi'Rlg>#lqMv%$b8%t(X>#=Z_=?>XF=&NQo]hTZCZ51(N9N#/w=V#P+<fM\"\n    \"Q;O`#&NgD4ED1).6*8GMbaU[M*obO#8ah-nDu^B#.9/nJF+C-KfprLFdmxmH`.;EAmnx6*dsUEM0ca;$K-ZUSsh8%ttrJ-5S:a&/=t^N#p^(eSZJw4C^<#v##,>>#eB[##?\\?(,)sg%##\"\n    \"#dq%4UM>s-Z4TiBD=_B#R7.[#N/*E*;v+r$e4NT/opc20/%?87Jwkj1=(e'&BU%],n(TF4$5)mL3Q6_#,TWhu&oC?#P^(Zu$_j9M7E3/1j</n/_a(GdA#cZ,nbb]>MIBougxYoL5h_J)\"\n    \"d?h3:aURN1*+d&5mIQX7JU278qZ/>@6LLZ-eJM^#`T_,`9[:I4>%AR#Qx=^@9%P#AgX<M1UHN)+NkfNMTYX6'm)'BdSwm],oG))-/DlT18Se-+je4N1)>]P'b^pM'ToWF3,YOi(gu2'o\"\n    \"a_d%F>kM<%BLgr6rd%##*h#30`4n8%&Nc8/59l'&05^F*^t[s$dq$x,VxG=77C#hLaSAf3$JYQs_n=/(*9d/(KYNV9Wpm/Vk-Y#A;aX:&V@O8&j+R*I_E.#6:0,o/'KRS3eYC+*@GP/*\"\n    \"%<anL$cx)*fDUCP*csm9?GbBaF-rZ#RJ/oqQ=?Yu0G[u@D`ob*bxNa*>J]h(nxsI)BjW*4$wKV2)i5#Hrv3V0YKF'4H)nf(sc'@M&l+Sn/_jJ'mUlQsHIG/L^ndl/VB')3t(4I)R4U8.\"\n    \"<2`^#)$fF4@x(RUWq;?#keJT%.1jr7@uLruDVllu[Qtb@V`T@2VGU)/Af3=.GbI(a@F879T)Gg-EmL#8v6olu/&RRNQ8uY[tO1Z@p-sA#.xvh2SRP7elRQ59S/Z]uCvJfLa<Hc%F%%$#\"\n    \"1`:G;)Jl>#6.[s$OS)'#HLD8.)V3]-`)RD*1A]C4?l`^#xa)*4jnrdcl1>c42kDE4Rx-x6AqXt(kg?)*&eff1%a$W%Bv[s$6%@W$A%7=+ZFAE#OBd@X_L`DHD`li958^4(>Z^W1F<M.)\"\n    \"6%'HWPCeV8;4cF--0:o8D0dPh%1w`GccMWmHV4b'l&-A#(nG]OtTIq-v50w2RTWL#?#R4$Ro*%HWaVW%X4L]5e2kUQb]RiTZXj:m'p2)3.^pf1wU509MDRi2VGdv$X`m_#.1Ii9RbXf(\"\n    \"x_fg2ixV@$8gE>PL[9O;f78=%)5###E_R%#n4n0#O6^l8T$<Q/.Of@#=c(?#Io>K)(LD8.0VKF*a[2Q/?;Rv$m1h8.Ww9a#'sUv-n%qk1dx+G4m-mm'_V8f3XWLD3sMN?5=PsD#ffWF3\"\n    \"g@AC#+g^I*0SEF3V2QA#xDc'&L@'E#TC@[#q-63`YiK-'$Fkj-I5qv-6Qf]%DC=WHBw/*$E%*TI?kad#5o;#,3>4w54h1=(=LIs$rM;n:]ej`*`5[)*LiHrUG>VQ&=u:'FfM1>$rFOI)\"\n    \":nuw'1g=_/Rs8k9[c3d/$f@aFt.2;&$[QS'#Topu`,umu'(/wK$#UB#jRNjhoemq(;+:O+C0[f64E829BFbsL?'ub`BLt8M/C^oYS)d3'^e%VU[9'O=fV,eDmlL>$#27$$9quw',4W*I\"\n    \"V.n;fM=I1(Tjln&X&'k,T,F[$n,M.5psc2;=_vZ#N^Xv-:oe`M2X&4OX#BJL>aQU%t<G##sr9R%,A5##DR@%#pvK'#r;+J*FJ)9/f&?A4ha-)*23J5/9Od4(s9S[#[UHp..3]P/NIcI)\"\n    \"PEZd3iet,hGs?]+@^E_3;R)L#o`#V#)v/)*#+apu]:6#c>%B?f8#$crs[uY&fKhFt3c34]P)-5Jt0.t%])cxX1SW%FYRMcRHi.^-%C`mjR2`:Sj3[@k^m^['o<@L#bD/gLx3XStd3d#v\"\n    \"$i?8%IDI8#]=oT%H:IP/g$+A#GVsD#[+]]4hk$],Y#:u$ACI8%0x5Z,GQ:a#an@8%kCXQ'kVPA#&_*G4RV,<-+^Rh%D2(,)J1i?#[TEhueAqgEN`tsSi9PZGhQ<THRge&+T]Y]%[^9Y$\"\n    \"1cgo'_QNF3.&H:A^]_D5>bfM'dZr=6FIDw[5b*i+rgMQ1_'`l'Hp%p%Pk)Z#Hu,qud1G>##1EL#j%^E#=dhRnApY'=?5iTfwLI<$)wA&=?vdI2Yxsp0vY.;%3fi^#2iM^#QEtT%793Y&\"\n    \"IJVM:;lJAerlPa=qYnr?J'9`Eh%u,vfI$&C2;#ERjRS=%)5###(pm(#nG5<._-5N'_qh[,UgX=$q<hx$>f)T/@2`^#*l0C4DM/)*>[e[#rO8U)C'Rl(a-]P/+g^I*&TJJh&gWjuqCG_?\"\n    \"%DF5;:pRkTYAwfuqQXP'&(bOm*.xW#'LvxXP3G`W%`f'I03t/d.5iPN%BV_SE8=(R3t]XP3QD4AfF7lE9='TR_Y_v[nnY6q'3(/u2s`:Zn-l+5O[d7mi<Uc=8Y#VZ'laj$m(d##D(ii0\"\n    \"BR,87jK%##a_:W-[qe8.WxC;$2M:#%XrEb3/aXl(d?(g(8/^I*vOr_,UpB:%HS#lL`H5gL_-+D#tpc8R[kRP/$83j1p:Rv$-,g]t#cI#CVSC]XeroOfleiLmKE>O(]8SG)f3/E#k#7],\"\n    \":qvO]QgFP2/f=0EEx4)JbKn*tkbo(Hq08$2,h+u#jYZ6Q:#'v>9rFMcj+iWrr9bJ#%d8L6-MQ3san`W#AmIH#L5.SB;H6`^5M2VB]DIoF$hdg>PTNHko9pf:/3A7#+LQ_#NV%JL0JE/L\"\n    \"fs9D3Mml0+rF5o$A*Bg4S;w[H0+l3+h9(,)MfbF']6=t$.9_20MFblAdDDO'jXZe$[ZrGuBu%?ACcn;8PXB#$BFg%uYrh/)tmG+M0bB*@<J[2L2rS`aE.^_S6c5n$fYI%#u$(,)r35N'\"\n    \"]SID*Euo(N1T%n9=9Ha36>@A4<LIw#0ljj1&c7C#%IuD#]A2#$O<(?H6;LY.%9w`*N1)Z#c1DVA2/qq8U[)W#=o7T%feWAh`8?_#;eee45GkP0fqHg)S(8@>i*FF56R/@#mAC/LhLYxH\"\n    \"gw*bA2RmMp,Ylw8Ie?.M*.8DtSh7TgpF1U1F6*r&4JUo8GP7LdV&hW7_YNE*^V>2CSM&S5$p=:vWaA*%HWt&#j%/5#BRUV$=@[s$;Wc:(R^Va48I`GM-8E.3&L(E#GY;H*Xv)E*UFJ^G\"\n    \"t*l:_Uc$]-[GOw9x1ur-679_-G,cw9L6nO(vTFv-<07IM)T,G4c9OA#I5^+4sf6<.hp?d)Z^D.3N,n['v*TM'&c7C#)$fF4ijaL)Vf*F3'1Mb7m1L-QsfaI)kX2I6P)JwBHkjMglK[DE\"\n    \"sZb]TD=LdRml'T0E6iI3W:l$,I->9LM?brMksm5&xaaU.d-/?7ufVk'b_[;8Q,`0(,4q58PVti()VKp7ZXi`+G)@O19Y&'rs5Mr0q2Qa3l?*?6I7'nDC+qGgBm`(,m%JP'v2JHDVWeND\"\n    \"/asGFA5e;NN#J.dq:Bf*XLUW--1$g)nx3f,k+0U#d4a*F>rDw<D/i$-]rJB+U'R)E#-9sM04hq%bhkgL>,w5O9cWc6SVJ)G9UKe>lif#,rfV;9I;aK4M[@lLVsDv#Z/CA=1gj5J]A[^$\"\n    \"RW(O'ctw;8hjOX$+_E[,nX_MF5<q[@5]tODxx<M(L49w8ch0%B*6QGRA]-*3ei:v#0(9UCIiO7:w,&[8X:.dA;eY1P2ObP&CIIW$ILgxXbOceu'I&5)ONE.=$,Llf]5m3'u.,W0qG)-2\"\n    \"^$x<$oB9;89=Sj0)`$s$L7###'DW)#p4n0#?Jg.*P[e<$Dfn$$c:pr6hbK+*DL1E4ltn8%/2Sj0kHuD#4?hM'YQJw#)H6C#3#>c4/wLG)dBXA#3^,,2*UYQ'6D.&4'D+^4?=tG2aOQp.\"\n    \"wiVD36N%d)f[K+*klaX%vbUM'.u`-(>%1t6?aL4I9]r8Xa4/<$EhwW$,%ScM)#[R#Ab3I)FrSh(,nHO(#kiD+9jqB#H$bp%4c:v#@_H)ET?8gudW)9/Jdw.0M3QR&W2*mN3Ur'7T^YaI\"\n    \"Z;)i)cbBd)7#1m(.FLw?t+l9C,`t,+`CR<8BU_P'v;E%83ao>,$'`+=1fZ>@(1;t%Afl>#):EX[/wOE(<vt:0&KCL188Xp%,GlY#V<w0#xpnY#qmo8%N:r1-xq#U&,aUg;mi3**9R5w$\"\n    \"<`=G@U;9T:tkVZ#94@)4^*,E=(a&#IE^4.3;M=%.E_6526trOB-[tk#p;t,>kxN3LL`08.DqCP8+m/DEejbm8JoH#6,$1&AiAGA#[Q>H2.A0+*s<RF4o=]:/x)Qv$Gd^01hbtM(J]B.*\"\n    \"[*'u$/qgJ+)f^/&8wxg)TbfL;u+OILRIn2LFnp;8d*,+%Wtkf(@60<-1X%q.#gQIL)LvU7:4rC&C77G;(a_n<%qJe$I&(<AU@#3Nw*5cM:f>;-dDDO'0]oDt6mAxt(/Lg*h1h&ODe0p&\"\n    \"oQ(,)$Z:D3$xix=m,C6;B2B.*xm@X-595H(j,8B([Hfp78uPH3EY8/LWc6%bqWd^#+M;$u@2MBo^66t/<7(p7UgkA#.3(M)H:kL;.6)I6NLej(MdN##CFE'N(T(x7#/eJ;6l)Y$Ip+3)\"\n    \"ru1'#`5ZX$3AFa*Z#(9.iE(E#xb1NKD,vG*@'2?%u[vo1cR%H`c1Zr%wx6d`3TRd$E%hJ`[R+V-))n@-wUknLH#>c-tQ$32Q30%#dj9'#cNi,#3%%s$>L75/34#j$URbv.&+*m9gbI[u\"\n    \"Q8v7&^5#-+'khU#`@)W-,Bx/*ioA;64Xjp%JM@dF''BOM(6Nu5xFbR0$&>uu0oqr$/9fo8B$CB#*^B.*+a5+%F%am/2CfU+uSwL(OQlD33,EILNgAE+jH@E+T0?VZq,g[uv+J`tGRKe$\"\n    \"v++,M*>5,M^.<$#4HW/MKTPf*p[)<->R9E#O0q,3fhM13FC=+3N;gF4P7i#7%hvE7/PiM#M+_^uN2Mcu^TJM'=,(tQ2Rbi(H6:((=IS$K=f&#(bu+.-v8$C#bnj0,)OH;M7NVJYU'Rw$\"\n    \"57###dWt&#[_/A=K1T;.#Sm29699Z-0He`*SDTa*1K6<-Ss5X$/eH)4bEM;Z6<w1,6H^[M(]sMM>N6##wclb`)Ga+M23cS74uSDtaBv@POHi^#(J:;$L#7iLidAE+emo7/+I9W7mCTqu\"\n    \"S029/'aVI/t2l'&%X0F.%DS7#&sxXu,uqr$-qO,/fKb&#)v=']F)4I)7u$s$%=Js$ax;9/)$fF4S<+J*3[B]$p<Wq.sFbA#9EA=%LL+i('i9c*PGP1T`YIL(+x'^#5p?T.MlFGDYh<]#\"\n    \"mpwd#&iTUuiZOb))&/U)J;5>#'n_Bsi<[X-/%d<-@2.b3&:&P&htDL']0HR$m4CV$OP(P&[l3_$Uoqr$bw9hLfv[(#51/Z$*@c;.1WnuLuIIa$5JOQ)@c)T/2g6*0EsH-)Z#d;%-l1T.\"\n    \"fl,<$'Q9k0+3ks$J;w-)=YYYu8?/x$>+-Bt*>2vuGm14'Z(eU%?BNvPbbZuu;4dBt1.xw#(xCT._bO-)+_AG2'&>uuNfUV$*Mc##IXI%#g@;=-iAhW$VWeA%2Q$9.9.M;$@V*w$;@[s$\"\n    \"#qVa4#%Ql1JJ=l(nX)Z#O-97;PAo7e6E_s-mvTQrNdMlu+RKp&Vs)a*'h%X-jM;k'SGF@qU30SnG[BGMD7s+OOakA#IPVkui_0XZj]Y>#bfW**'*=q.64NU828Y:QPt^#Z9E@C92B*x^\"\n    \"vldu>S?4<-*Y+R',e^>$iL0+*P1[s$KK(E#a^D.3_)l6/<Cl$gm]d8/1<<E4l1f]4o+x:/x-@x6J=On-[NxriW8BcDwPv5Q0RSc*;Zpv0VDUYe+IxGg?TQ<qaf1bc:8(u7SZk=$6=<5&\"\n    \":=I8%T3&e*J^KB^<Ijs-'d%.PIri0E&kwjOeE:=S&cj`u60C(juf&d8`S[L(<_w<$E=.[#ZH?%5qi]Z?CVJvL3w'UCmkB;$,x)5&$Q<Ds,cqr$:b/2'-c:?#RElJ(&uBB#8;YY#P<<L#\"\n    \"4r/.$W2>>#MXkAuZW,7$s;9quK+q@MMdFD<?5eq)F,>>#1m=da9(M,;+c`$'d;,##<II5/n/Tv-;ntD#SP,G4$P9F*x6.1MwmbU%L?R)*8m+Zu%v6jmCsg?\\?@l`'F`WVx1>'1EH_tp_4\"\n    \"eh5UCA.4K50.X]=`ks0p)%w@=x[DO#dOnG;Z]n&0@W+KL;'Qr>a.AO>SPh%Od(JfLs'^fLQwT*%+$-tL5Lo9&U_?X-YR)v#njxw#%aa@tBow+kdpn3kDq+^$JwF>#CW$K#w%bTu'b<9#\"\n    \"'8I6/8:r$#>0_1N`f+E*:/5J*5F>V/BVw;%x(V:%?oCkL);Hv$$cGg)Y(^L(MCr?#a',V/=SsD#)'xb41M6]6CH:a#6-bn/o:^+4t++E*[j=?-:spb%T;e%'h5hFEh&7/;9Np@-d#>K-\"\n    \"e'bJ.e-]hMiqOO)/b,F#/9<W$<A$Da?J;T%OQO]#1uAW$)4b^*R0dN'X=jT`P&_`a#[12+wn&]GX/nvA+`ah).eHQ'2,R6Lf]H[':mh;?4^G>#:C[W$4vP$'WVO`+bo)xb1a(v#:(;Z#\"\n    \"XnW:%(Pa]'8jCZ>'/###9)g##Z'x+2XVl%=)6&##BS%W?RlW>-+Zp;-o4oi$m6it6)c=s6<&$D6RwJu.xL]C4*utA#K-bTB5;@A4r]qv-[1ur-RLn20sN%],A9uD#*e`Q;hi)T)BK7/3\"\n    \"?f,VQX4CrQvU5x6'?7D6G9B?HMti?#p<Eq09MvuJ?X9ZDg3oq5;[.MtG4?H?OlUA?gG_Q&*3930.A5C0bsTQ&O1,EA2A19*7gn`6o.$5]Y$Ci1>d8%t`AaS%6[#++1:*`H]=eZ#Lq[w#\"\n    \"I;:kL(6)&7Hg7t%mCNfu*NtK4;vlZ&a096&s_]Q0a@uv,?$6u%049FM6RD0?J$###$&>uuQ3N)%SD-(#Pf5x6Z2E.3rHV@,gV1#$Ub;P(^XQP/Cm:9/&'k?#ZmHl1f5UM'72i?>vrM>#\"\n    \"es:AF=o8.U`v8%hk(5[@]SmCWg8mt#e*r^2BdHPJ.piJ<;=D+*[1@cTrN4EnYdOrgcW7c`Sw$D-^qJ_u.FRb#YkclA0Txx=NBwBAul-+5N`G>#<#(_SbhT&#aH=3G:9St%A9GJ(>u###\"\n    \"FctM(8t&T.:_G)4@>pV-1:lHZH;gF4i;w4A6>w;8Z7wK#R)mTiE#<?8ev%:)%JklAc?*<A%%I2L&4H?$%eN)ld/QmD@^K/`H;ou,*p%30.sgo.';:8.T>%&4vcMD3e7#`4^AUv-?'>/(\"\n    \"-K_D3.%<?#msAv-T.]w'md9Y.8T@D*,HF:.cOr_,94%s$os,kr#&IUQ@oBVF`He3iP]L-etqvEhKTxT#mn,U#+dSa#B')G;'FidA2Y?T.5Ic>#cjIb/YmiM1^W8-s&<_IQ:*9+dE&DmE\"\n    \"4tbbK&CBqu$KPW/AwJauF(bCjKnOT%a&R3o8SHO#r>l(5O;G##)]$s$?7###-Mc##=(V$#e5Z]4(VTN(UvPJ(PNkA#4<0iT*f#Jt5^4,Va->1p6Mv1'/_(/C:tTfLatfRHBb#A+1hm[X\"\n    \"JEciK<<-v5C@n8.J?-/q=aUI*KG'##d,;o0eAGA#PJ))3[qwm/lbtM(PDRv$Er8gL+HGA#wCvhM^<&fN:q9a#N&u6/8:=m/4JJC4'cXF3`c&gLq[i8.[GUv-R#SF4VO^-6P-9_8IA*F3\"\n    \"2=L^#$)A9(vX0^#,4Vp.^I%SV+T+7*G&5^$GL%@#]f6[-VNeg)#/u<6FC*e+e1in/nqs9%9st_/c&E^#XUL'Od;-J(%h:+GN1B%b6?q0(3gErLCSJ874SY>#g13x'HKX>-(,&L([;`0(\"\n    \"w(2k'boK>#NQA#GYiC3(2%32G4),##/$Jt%S6[0#9->>#Ht%K:MLaZ6s0_F*-JWD#JTfG3,DsG2:2Cv-Ut;8.J-xP/C*9Z-A3gg1<)'J3aiaF3x1f]4_4jlCIN2L)?]d8/H.,Q';Fn8%\"\n    \"(YE^-e?T9V5tA%bC[39%QUW+/<(`w,51lM(Oci?#@^[h(T((c'Eit]5lcHS/&:D%,>6T[u`ogI?%2n8E/LSID[]Y',1*BR/)p4_5&]POBTjo3/D=EFEtlOw9XWCh1rphD-oErk%mD*l$\"\n    \"o3c0Lh6KW.aCu2(p/G^%+i,nAYho:/Jq;*4rpH&><6OKSO.tM:7rjT/<&Dc+(r=*G`'hE5a,4v6h%se5*7ZR&)lnT.;4i$#[Z>L1jAqB#D@A(#H>:Z-J+w'&Q2kA%8CXMKQ`_XulTSi^\"\n    \"T^st]-+>DN_#<I2#Dl4<(Wn_s3nx5u^)`?#0&dl(_/###[A'$#wNIP/U5Tc;/H&##P[NT/J9`Kafl+G45YIfX(F_F*vbLs-S(R,E)qS,3=gHNDbS8f3@U9Y.F*cI*nfjI)v;Tv-[P[]4\"\n    \"bA;9/nY.R3Vj*bNkG8f3i=/T%qiE&F_)n/(xFEo&u.38&X5^gJ/<<fEK^,X7Y>&4Ej8ZF$<n[=TcWJOorJu.Se+hcb-t&N*8E]LB91Y.)M6Sk9h#na3,W]H#?aT40uor4'vB=r(M?Ru6\"\n    \"(1736Irg02e9O5&`aQ6:(P[)Rtu[L*F);.;=kCmFdOW(qbpEA*.cCxbYvQ-J<ka5'K+vIDS2DL+Wu^B+csf%+,(/h(8+CRb8;s:7n@p^+%)###6p4/_2umo%<p&##ebLs-<@Ep.oghc)\"\n    \"nRbWqqVI&4v`;)3n`WI)iF#v,m4^+4['oP/Lun$$hP^G3RYCR'9Ah;.+a2@$b^,,2Zah-6hF7#$f0JW$9^d&Lk#j&o;>/vQYtpdJ@]Tp&tv:b='p?b+v7HcE'J-ASLCd:AJ1hl'b]-=0\"\n    \"Khg-da*P`LB&sl0CwJ[#5%Bc3PbCJ)*[fs.TQ`9&dQ5-?>d8T:=W67&a5#sK+#/sKwDL9[sGb/<;Bx+>uiS-)@btX.-wcV/HDYb+UuXfC>fk31vR[w-t]Sx?wfu2<'STH5(QjnDNAOq0\"\n    \"gvhg(cgOJ4HlG>#BsXd*@Su$6tY=G4mX`H4Ji$##SDMT.Q3=&#FuPP(Zas]/%M3MKj9;X.`YH`aCP5>#dDDO'w@g;-4=Z<-dX4f'T&od#d=^E=U*^+,K:HuuHm_N'?_l'$b<3$#bd0'#\"\n    \"Z####-svW(&+6;-K'Ch1S6j?#;#hv-8o<_=&W`B6;O2X-UB%9iN:NfU/T87R3c*cixXkA#E2OJ-1@tVM7Z/vPTJ;7[o,O44_OFO'0+W3`a9W$#/:7R(u<aW-@J^0um2nA#l66b+*.Iq7\"\n    \"@6j&-Ipec*.X4E,h>6e%Xk3>->N*J%PO6q7td?6sZnvu#w%>>#3PY##S=ho.a0%###wT:%:2Cv-f8t1)l$U/)b/v[-?S<+3vZM`NB2B.*tZ'u$<3r8/=$<FN7:YD4=Y-&kpJ*.)-u#L,\"\n    \"pUL8.,fW.tJ*kS.3xq+;Z=u.L*.L'#8.pFM:Hq8Sl(Pe$+Xvr6LXW:d*Mte):,<>5eb>@tgH*Y-p/t3;dKke$iUN0v4Y29/S:h(EB/GON'=bNlCIC(%M:Ji)v5#,2Rj<J:;m&##+IcI)\"\n    \"Xq)v#&6$hcNG.$$nEZd3wIpr6'K#g1dm`LFaCr2:KCmTiRc)1)9@&s$ImZ)*+)TF4xA3jL+LXD#.WrZ-_]NF3@GO.).rj^-m_imL<>Uv-Z)`3X/Oj`%@Dh=#k=RvGPpO9`ws(L+kQ'^#\"\n    \"_YUe$03#A#`%U)Mshs.L6(SpAG(>d3s`rM1)sN&+v[4'AWf`$PM>hU_ShP.@WjnQMS'aQ1=-I_u6?>aXC[@##xoaEu48RA6mJJvL;:@=ljD,A#Zk$?$q(b1BwN<mLFo29/?D`D+@-7`&\"\n    \";,D_&@IV8.h2S60&Vu(jA9/J_=%Nb.g*Hcu4c]?1qWld2^2PuuSd]*%l8[0#vTG+#9aPEn]1[s$6olV-<v.l',=.6/x3vr-*%@lLBi5<-PUIq.x9%J3?>M(&c3YD#Vvw;%IJ+FNN*QZ%\"\n    \"GEgh7eH@Yu$oR[uU3]]4JL@<$$ue[uMsGa*'9tp%KNU+M>]h+(EqNYdXet?0$lwZ74F>HMeqdi9ve+%lY^D(&0Owu%&),##sD3`srq5>#,7s#laRDt*L[%@#m(9gLJUSx*;-JY-a]Wk+\"\n    \">JMYNd;-n&hH]s-wv(tI,?Mj9YWt&#BE^:%UX`v#CXew#KjHD*6@@[#.A<j1I,Ih(_gp_,EJokRgZX;Mn1oOf0jGc2m2RS7@F#-#5PMj7Ke,=s?^>`76U-C#4.r/$,L52uWmNT#W%720\"\n    \":+m3#?Q'`a?*9U2poteuhDHld)BgqJ(4ED#03MiMtYQe%+w/sNeVio.uFB_4hF;?#fc%t%9fh*%wOmZZ2Sk,2Qs@HuL^LwE$rg=Pg0$_#_E8MZA<8MZY)uIU%AeuciGsI#&frlEprduc\"\n    \"aY^V$>h=N09(V$#dpB'#Q_/A=U8=l;tc-/(*O13(KVFI)]$Aj0LNv)4qc@A4Rq@.*CZ0S/2E:ODxnhHu-PNh#4CmElS]kUlF_s?'3`>=-g#56'(5?F%)v)3NWIRAMmm)($KAoJ;JFnt1\"\n    \"IKP`apoMIL<=1J)n#g*%FHD7*N####%p=:v%)%W$=ivA19xL$#Qke%#@F;?#R1E+2bE1,)kg`.3Sm9u$c:o+MmwcG*NPr$u<Db9%DYGSRsiVIq7RT_c=5mG2Z07h(->&a*Ri:Z%kvf4&\"\n    \")[/k0kGq'u6KDGu=V#O*s?5oeo9*?u+Ci*M?QrhL=&gA$CGFV-f+vxk5_fi'hmXc2WKBD3]s$&4]_d5/+'PA#Y@ZV-=ZrG)jCXI)=]d8/Dd(T/x,Tv-=D,c4]WEb$Hc:@#=>+1$9krRN\"\n    \",k4;?1?jguwt?Ku6`6wB2FfI_eG?2)6Xo:fS>mXu'VvW#TGmV#u$Q`a3c(k@T5EPA+AN:B.Xe/lV.5xC3F7%E+I1;?3I@$Lh7]Eg#l`Jf@JnNX9P^p7R8gqBcZ&%#w&U'#h^g8.N#b1)\"\n    \"x_'B#m?&fN=+Fb3w_H>#*TE-Z&N[L(Lov[-oi[]4#UNh#R?)U%Q#^xtijUfq$2;>>$Q:GVVfgP/VKF]uN7Mpu3x^m&jJ=Gi31gXYHb'f#iJ7I$*]&&71u'a>?D?Gi+2;>G$UBuuxTKY#\"\n    \"%X0##'Jo%uPKA70%9f1Z8_jT%cc8_8A_m>SC:o'Omcjr96@_'#0GY##*SJV6J+65/`0uJ1h@^Y,kh^F*s+K+*'4(:)&%ff1r5B?-&*(V%u>@8%cO:8.cNof1g2jTD/8+3.'#QQ/F]mE?\"\n    \"<X8<$27*,HGV]N#RLV(,9p?]=p.a(6S)JX/M.[%b#xoYOQq#N',YKP83^eA*Y[q+SvT_8csCO8)5b;[,W[oQMD&EU%/`ZxLVIv#%,wQg):N?_uSwuWUarPS#AgI*Gd3arY'+h+>I31R#\"\n    \"i8%P';P[Hd](]s%]MR]4mbeu>@:D3k-IA8%=f)9/vBhhL#N/[#g7+gLslE.3&_<c47*YA#+2pb4=K?C#[RCE4jI^vRi2k]Fl4U7D>)rV%+PMw&fM0xt[j7xt<=q^+pg@f#(mmr%fMQr%\"\n    \"vP:U%PCqN(H*c01jF^+*m';D+q@MLb?pQ?;95k0E8>Rl*Q#pa3H[`V$*9,buIx-Mf=$AT#$,<D#B`5<-GLnF)4$]i3l1D#7PEqO1W6^gUcG=k)%kA<$e9,cIe_940%E+++c@>JkW?jw$\"\n    \"8sDu0ms5ulK(]qFV=fV$Huo'&R<dAf[%v1GlRfh;^Vw(#&,###OP)mJXww+2MTw.:9?$)*<4i?#XIS/1i%'f)FbCE4+87<.,u@T%S0SP/`S6C#-opr6R5.)*atr?#=Nc8/+gB.*LEnb4\"\n    \"0<Tv-g<7f30hd5JhgtX$&HU/1>_=w$9q'&$LZ-YRh,0mQh&sbIgFBpR7Spc5RghZ+pb+Sn:3Pk09Q@>0sc?_R$V1@EY<qr`fP]JHflPp#8[aBuaT=D#AU&C#udRuK2uoXCgKCj@<)8A#\"\n    \"gZfk,5Y[G,)8Mg(LW>.2@=0a)e6t6MQJ;CaHWx(RY9>hR[5qbQ?Z_B;fc'n'ZJp(<(3&##I^u,;M&wC#NCI8%Q6FA#jAqB#TekD#%8o]47/rAMNBo8%)4`/2hF.$AcaO[T*H'#GG<Q_'\"\n    \";47m/*UZY6]^]A,]l8w5Pl?%-N5J$?)jGB,%X5R&PuC<$`'FcL?/S=uCX/E,s#ULN_t8@#nV'c5'/=I)G^3/M)RH?.aIl2(7ab#-c-;J)rQgA=ew<aa,W]mCw9hf,[;G##rfbq$]5###\"\n    \"mIa)#*n@-#:XSF,$xXI)D*'u$5V/$p`7%s$Y_ww#w*v;%%9&ktme@8%aw.[#=,%9.72W%$'jE.3qn6x,F?tX$c?XA#n,U:%*kRP/AG.$$dCXI)9:jMgA>SC4$L[+4^dw>@bXfA@6PmV8\"\n    \"txhG%?.[8%KJMcVF<Qn&lT*)+FDEl$TUX5&Wtw8%rJ?R&@xmZ*?&eA#2*`v#Bem@F/K8c*2w0-2aw0t%SMdlJ1a>#$QH'u$d^a5$<LjP&8IO#8ZI0^7<L5iKP7_F*C&U9%='#3'K-vju\"\n    \"`PlE+j(j4'8CJ[#ncBqWQHq/)6M1v#kx@l'R2qB#>nuAu/C7w#I2dOG&eQu@far+*s1/1(6^.duelJW$_<830pmKon,MlY#b(JfLX`;<%WuLulL8A#,07NP&xGYc2)B7JCMM'##`QsV$\"\n    \"TMrB#%)TF4o2Zm:,ce;%:2Cv-cc@A4k&B.*t:7@'v)@d2I$Jw#9tT&$qU5l1I1%`,NAa[(;Jh@#wK.v#x+NK4s^7Iu^oLO'rg%[uTUjg(@5E.)h.St%;pSU'ro?ct@XDh'Zhi?#<:[lS\"\n    \"7wHY66Q8B5OcG>#/:Y%51#1w6cA5J_q[3v6RcD)+CDJP^1o;&5w[dR*sAfY,+;J1?&n^gGN>q1'8Qr/1;d,U.:oVh'&@BiK$t.[#9n.[ux;vGET&xN1%&Bg+jw,;@nh?22w`jJ+XhX@>\"\n    \"cuM[$F=j<#uNi,#i4n0#h>wmi.%o$$qwkj1L5=c4Sa]G3*tBp.G$5N'Y)c4McaJw#[(KF*ZY7%>S&vG*sKNh#],d8/OD^+4.UZd3dbL+*Z#[)*Jx(t-'9J*Nm&u9%pXNv66Jg,NXkep(\"\n    \">fCZ#nKjJ)-f$E5CT##-.V@:/#SVc+2Z>v#^+(J).c;V.7Rap%wN2H*tYf5'@R*T%p%;B#@Ows$tmQ7Aw;Lq%7ScY#qr9R+Q5ds.N&X1)2[t0_<#+.)?X1@'l4'TW0JHv?o_F5ME#R-F\"\n    \"i'K=T5mlT%vs-C>[vP9%#<[M'aTM^/OJH>#1VbW6qd<^I#3Fb+OH^Q&n0;@,')wILmUbe)LZYN'xR*@$[5&*$n-b1):26a2NQ.0)Lk/4)3RWb3;K;;6MV7U.R/?>SOaRq.kB4##TGdt(\"\n    \"KG.on,j1oni4n0#26k-$&/]/LHCZf:<1(<-jd0'#4pm(#T%T*#u0;,#?<x-#`G_/#*SE1#J_,3#F*NU/vu/+*9F'Y.(c'^#&PF&#hP'#(RY4#f=&l4SiF[RSNON:%q2WB#g;(?ATUh(W\"\n    \"9Cc'&uR'^#NsA:)083A'@@T)tp0k3GdVbfLv.K;-;-[>P0UucM0.G(NQAYTR+/I]-fI8F@$]'^#gX[8A2(5+%G^A:)/Mo%um;nqMp7;J#rDQ<--L;=-8@G)Nq%GKM7I.&G,Yu##*f?8%\"\n    \"1G>##9(V$#Qqn%#otu+#^`-0#q@$)*^8p;-a(;T.?Y(?#gJ*$5Hq.[#Ps$d)-<Tv-<)'J3J29f3.QYx6;d]6%>Zc8/a;T,3fE9dOHYb/Mi1V7BFdZh,aNI,*ltn8%9GtT/Jc7C#[`JD*\"\n    \"*DWX(YA4Lsco]M/-RZd3'U_r?'I:VZI&9a#'@&Y.S268/#w@R+IGU+E(9sX.dxZW.TnLuPmd.F.neMZh03ZH@(>2:2dermL-BZ'A7Ok*%$.>T#L#4AOfMQr%mcd;%wmlU%8N8i)`Xis%\"\n    \"is#n&4i3#fa)i0(Tv$ZXeR^8/o2%Q/QX6>#[A'DN6R_'#IaF52)Nkv6fRbNlj5x9S(qKH>20Ne3w/*R#26]e_%pfYH,f?qM+E-73n?GX(UIg9M6`Nj08']5Q%kA<$u[=jHgJb<L,0%:M\"\n    \"m?;Qp'E#hLrR^5#.e;@$vx=>#9oUv#W=18.cGMfL?$85/GF;8.uiWI)7#WF3NP,G4W:AC#Xkw6/M&e)*1rSfLigTM'4C=X(jNRF4ae_F*L@[s$jWm3+]@i?#/DnA-[BpK1@XI5/W>3,)\"\n    \".9+G4:X)I-k)k<:ON[;%3ar<1Dx'+*<r(v#22HX1`aIh,h]L&ZY<jg:Z0Ev6B#wTM48Cs72tOn*0,Cs7R)e#6Vs'Y$Y/p03.,:,+xGn)4jUrs-sM'Q(9O>PNdN&/N57TauO_:@.c8fL2\"\n    \"=G[S@kMH_+.Ate)0x=M(K`g&%-Mq[kXjAn/Cs_N'[]<Z(KnQG<mmXP91g1&0FUkG2o0`n1W2O_.%'9sNPjt:.bp*fMvBxS%/`Z(/Y_.9E#5G$,5cg6EAiJa#Br*0;e1+W%lEQ)4SZ#<-\"\n    \"r#lU%2%*:.)VbM(U6C].<4kp%L#@a=Q*j]+rk'B#d[C7'B9VjT^>Z0+&KYI+_3FS(pKnNX7Vx9&/+RtJ2VTe-1e]-U7qf3*b#be-E8VX.g9qV.5NI&#u_^>$R[Tg1%i8*##Oi,#)c[:/\"\n    \"NhVR8.>lD4<)v'&Bap_,q-6QU(<2,)4[EE%+#K+*peH5/l%AA4SENJMIWx;%w'^:/<?vchs5x/ESS9clc24t-E)2n&Eo1I$CXNl9hueYfk_I`a6Y730rZ29/w'2sTDCZ^6JqZ=P*:$L>\"\n    \"1_4t$UE3t-%REl9Q-eYfU&Af&f&);?6^&##M^5N'7a-#5?]d8/OM>c4*^B.*P[NT/@Dn;%jo%&4_@Rm/]]WI)^JbL)d&Z[$L.@x6b^#V/B-Tv-%%(4+g+]]4M^Ks-x2shLMtW9`5w(($\"\n    \"rU830?U&Q&[#ff36k@G*8(JrmK?D4'a86v#6t^11XU<kV*ED;$kSAR1Hw[],H9S49cr(,+rB@%RU3`,)WDhsHgEeF#B>Y/_G+pT%rw@S8[grU&7]fiB9>NG/52<Y5eR.T%lUF[lfL0K(\"\n    \"dne&RAw's-<eJ62NTE)+=xQ8%BPFH=uxA4EvkdX?25f;6AoUZ#Y'LC'XbZY##&5>#8hruuLU5JCXT^`3C0Tv-GTqc)5WLD3VC9a#/%L_4u*'u$bH24+a@i?#_FL8.R<3*.p+WO'1]DY$\"\n    \"dWe+4SGiB#LW@,MmdxZ3k6f[#+=tD#iT&],C;*P$6gpR/11xU(k3>@$jp>7&0gs5(:fV-(B8mb<8GN@_`u=?,$Ai5M^j/:VSsq:/n93j1^mb>-V/Eo0Obs5&rLMulG5Gp`Rf+D#CCOv#\"\n    \"C492*)b<H$G5xx,-l3`u$h5b=MlH>#6<Xd;Wv8@@2ju2'@3Tq%kINU.0>1#]JT6rN0)X[8)hoR/:cVZ-_>T&Id@WZ#U>5tln^dRP,ET1TK;ne.Uff8'B*&v#uu=>#fq7T%^l1A=Uf'##\"\n    \"w(ZA#6JG8.<4i?#B/W;.,b&T.]Vd8/:IQP.+E6C#axQ#6(g&KMuu=O/2^A.*cmZ.<$vi<%o-3v#Jj:9/IR7lLVX190Sm1,)O7%s$-k`*.Kf@C#@Dn;%@E+v-uLOcM9^e*N)xBF*G)IW%\"\n    \"H.k.3FurA-6C6j21l/0:wc,Aui<'+&5np:/hoNo74CnY#B2Hf_uwF-381ou.en#ruwD'x$3%]v$xW^wi@ZHD*$T$L.%%Uf)7r+T.mCY>#0t<#-n,LM#^70j(4?t<$PCk^4KJsvQDTR4.\"\n    \"<@qSo8E0Z->x<5&GV&f)v[DO)m.Ae)uXdR(q@JZ,J+rZ#90&'5,?0UR^rjx17EnE-UM2A-4e2E4XaL80k_PS7`nR<.Jk7?&.Y4N1V-=B#Hc]Q*1;LvdCM@5/0i_V$U9=.+Jum:Rmsj5A\"\n    \"fVE]XWdLn:7j6D4#1Wi6tg=r.$qB)=+=r<-6nXucg*hh(drIo@<WY,<2Qp7/Wrb((-U/$ln7=>5';G##HpP;%5,J-#(Ur,#Vst.#<l)T/Jj:9/&nQ#%8>GjL_lXb$<r[@-eLbI)@=@8%\"\n    \"jpB:%HXX/2dRfx$[a+A#TwuS/>2RB4pm<:.Ff@C#Qo=Z,c:FI)ACq/)@5]iLqbZ##^^D.3l[I,*BA3T%YNNH*$BO;$n,li)<U<9%K_R[#WSABFrm(h(kMd8CTB-Pf:g0:@OL]t([H:-)\"\n    \">ln`u'`980mSB3&RH(&$W?pm0ovb^&)C;)ET4;^#S$c2$EWQJ(s(L4ob.(dunPS[>Sh4',j#N@#:q/m]l5/g@0/AH)jo<**AYB]t'vO-)d]dWmbACmn<tW]Pm]<G'(5w<(=)^,$8DpF*\"\n    \"]cm_uxiCZ#$4VJ:;;;BuKO+018_8JUhdB/1G/&I&U34J#gDu$G)c^2EFN's/$PVP)Ce>OKGZ[8%/-Y`3'&>uunZ_r$V4=&#2dZ(#t,>>#'U*r$H.@x6Kf^I*%@,1Oh/[D4?\\?EE4w'dd3\"\n    \"4DXI)Qsd)*+^Ol(3SMT/xwmt-o1)E4q=@8%fSc8.&,]]4d6,WQ=xC;$L(4,nf$-pNa/bd>/*Vj;<*GV#d4R884a>s4U@e3:4BhA,R`Sn4cM4/FGPe0jU:WM0BpWv-lb]+6TcRh*eOYrZ\"\n    \"3-UtV&6QSsS;&Z74X7lYXoWi?YE+QB-iw-.Fn]`g)i(Z$gq*)3[,Jfh@*7uuvX?vKK_:aQ($-v.16:_,,8`iDZA,j;X9c(do8g%#%9q'#>bFoL>*#V/gK9t8_J8f3F<Nq-^wL9rAOR=-\"\n    \"2p&f)*?Tv-e9qfLt[7C#>%>,M+@j?#u^3H$CB&K:et*&%$u]A$YRF31X<8,U@W'P1gt.v7_+MT#Uu3H/3+te)Zq8%-.ks`<<$;JLnYn:9[3>kMl>b%9is?.<>FDJ:BUbT%L5CB<hjq)3\"\n    \"vuFUWt'/>)j'JeiBeXahYvaFHL^o.$JtQcQx,_e*Dgw2UQj/b>)I+w7;-a0C6<kA/WsDo0wtIR&Q)###Tx^##Mq7D<NP8qrw'n;-i;Ch$80bD4)>x;.^l8mA;;[GtnYl]#Yk[s$TRX^,\"\n    \"l(TF4h]q*%dI*C&Z%Wv6DXHu@Yt&&vU[0I,RkJU/;h&n/?7IW$4eFL>MIHX$fH&n/=#4jLnN2T7K_9i#VsPn&sd/W7@w,n0Oe#?.,GN0(ptp%OLmUd,GoPLMPS[<?6_Gj'#i,,*b6A[#\"\n    \"^wU@.<KhI.<Wfd#tLke)rS.l'9NwL,-Bs-*ofqq%Z/]iLh%8H)hk[@#P[7Y'V),##Ta]*%b=e0#*->>#GcK+*&D(ed_fj'&l`.$p''PA#Q<O7/#0Tv-XtX>H)P(C&;<Tv-k[d;-1.>j$\"\n    \"5H7l1I9fOCu=Xs6?W8f3GU*v#OmuT5dguN'Q^3@,#6-@7'u2R<l&lFj^.KF*rI2r.&8lG4&PCf3.SRx6D*Wd*`M'J);Oj'M<mn0<niC97UxiC,Eb#i(@$<V7-BwK#3=juIZJF^+ZrI21\"\n    \"3ufl';%)f-^oo>,#p&$5`@.W$^/pa+^%R<.b0Eq.%0lP9^9#n&LE0oL_KRK)Xs^r.XCJV21_QCJeh3t-ja2?8v1#V7hF-Z$rABW$TkAU/:bsm/@7IW$4hXh>O[mt$g<8306>2T/k[1T7\"\n    \"LeBi#V#m3'sjJs7G18j0t]wa3VH0U%Zu0##M=aQ/&Y#N'+K%R&IL4K1_2j[.?gdF/:tdb#=w>B$mfZN';bR)*BUsM01I>B$kx%-)kw<x#KwBP'M2###V7+gLF0@M9/*$5AGfk(E83LG)\"\n    \"oYCu$M:^v-YKo5/bAl)4x`qR/c(2p.Q/`:%U#q.$Mh`S.ksfK:0bPW.cj^q%ev<L#5r8I$*-tM0_5(D)Te#B1O>Nb6KjY6/GWC*<`:*UUo$9#i,ZLIpSm/Wlux0k1TxF[8@KpT.m8be-\"\n    \"Sg7m1:Fbg)v?_&='<[FrZ01bUR:]WiG(>2'x9GxF$LMVQ$45V6'<(#curx=#S`%/LwAC*<bIEqUp'T>i4AnFqV#Ksl>MaK]AN'XDdXrU'h./Q0c(3X8%FSe-K]`roTj&Wl=GWK]BH0XD\"\n    \"chiU'h'FO#vf'TUth95j/jv5/SlfY,Nc7fLOS9YujXARePSr]4$1CfCH$G8@5>So7iT5/L=./;?\\?J,^XZu^##a'*20Yq$##n0;W-rM[L(%cK+*[jTv-oUFb3^%fC#t>Z&4QD^+4^mCD3\"\n    \"jb?X-n*vM(1t`a4AqS]=F#P@ufkC*JfpAR1BJ:5$nreu,ucf+4n0?(7(TPI)Q%(D``/uqmN%0AXU>qLCjN$3:+SWXu01^X$o=w.$V5r=jNs`D>bX<l2$X+V+`?pF45P9Uuvfmvtp[5=$\"\n    \"0x5M,<n,6#%@V8&UW+<-7#W#2r2h'#cH`,#`Mh/#t.,)MET's$bB7f39`p>,KQ)`$o/T,31-3o*h_+D#s5Tv-h?7f34jWI)]]-f;EmA,3GcV-*T>CR/NDn;%Ic'gM]7XF3fs?i;AkG,*\"\n    \"=C[d3B-Tv-C_^-6%fMI3?DXI)ogaV$F4[s$Ljhc)l@<>.Dd(T/IFp;.$xH1Mgo=c4xO[t1i.<9/#RU&$j+:%/&,]]4@hJe$8uj-$sI6Q'x/[iLcF5gLtaW$5*>O&5xtHlL/=B60447?Z\"\n    \"/CK606CnvZKM#<-vWuD3.<vbuRN-Wh.HHID$m_Y6&1v`4C0=W6^4)&5CP-$G8t0R(e/n_l/$U/RWBGZuLxo^7^5Ea#3cD^Bi*7M2th)]?lj@+4teFG#Ier`5q>*E$Pgab7AAT$92op'5\"\n    \"i&<&AD0*>9eXG5;>?>i(@tU@8ISBF*FwN5&h4Jw>93Ea+B#)G5TAI-)lw03(%rk:.;cpD$OD%1219L=>`]=n0Sj:21q5UMT*<ZrdILV*Z+Xmc>L%Ckuts(/3>X%?5fYAH#;;x$%L4q%I\"\n    \"V<Q5kNax4]&_E13I>JbuxW3rE]pc6Fecwt$ih1J)ccYiF;iQZ7N+KYGQ2o*7)IaU8>2oF#hXLB%hh+/5@9D=UGcjC,Y0'u$EHIK)[doS7n4@W$Ww@@#S?4t$%'7t,i.pp0f#1h$8iho.\"\n    \"Tb$##K+`Z-&gkk<UDG1:ro1I39t6H3)`j=.N.OF3+RmZIX.moRCW=siaT0rBRk:$Au-*%S&e$`VDaSV?DH7rLW/mf(V@K*32kI#-21.)QpvRPC+O(]b']7sLI^jLFiD8k2KMdc%H&>uu\"\n    \"`<;4%Jd0'#IA3I)v;Tv->Dn;%A>Mh1o:gF4?DXI)BGDC=h_e,;S7[x6J]B.*9]hwZIYO:m7A)^V;'bZ^C=@/a<$)X'lY<C?<(LC+JmAxtO6+b3<-W7[`dF%GolN<LLxt1+Ok8[#1i?5/\"\n    \"NPUV$5XhJ;IYJs6b%*)#+Oi,#urbf()5rv-buM[$(`d5/;lm=7,R^fLB]s?#kmRF4]ke@#aHwE.h.q.*t0qS/)*vx6?CbF3O%<9/+&Fm'U(KF*-V&E#*o@8%$<(C&wgX=$S-bgaqI=_$\"\n    \"-`QP/bD6C#[T4p8(HPH3onKv5N-_C4eTNp@*@wX-T$cp<)3dC-v(8?5l-Gj1[qtet=8XY5Jjxu.opm>8-9h;-n14e)t-'$HJ/6C5#Kh-4d?F5&(X0'-m>u#Ah@:hXNf89,r[@=1]mou.\"\n    \"L@rO)@*ha3TINh>eX`S%[0xC<j@&_-b2B6KLN?_JNPnXlRAu7/`Lb%XwYsx5CK?Z.K$tI=<35W76h$H3/'k?#saCB#eU9Z7M<c$..WpI*sh)mA.v$<f<]cY#88M=l.o6s$hS9%kd%$%5\"\n    \"Q[)l(PwJN0x`6]#hlQX8XYM`-fal-j:#?%-vX)V.J(Zm:%w6K1NJiILMcFd=W`xs&cq;s-t1932)BAE+[Pu7/qpUc3D`&$5GI<U.(v's7AI=NN#pu&#fYu.:RNRb42^Yx6#,m]#vrwD*\"\n    \"iZ.TA/sEd;8Fn8%/D<j1D4NT/`Cr?#mbK+*'ZC)3lVc##Ti,o7,vdT%X-hT9b1Ec$=O'c5^rc&%MqEZ9pw1Z%OM3T#5#1w#t[0B+6YYc$T6f--3rYa$K-PB+QN]v5/<)G#b=L13V.Lk;\"\n    \"Oja($X3(:8%?&'$ks39%0?+,4NCmC$,ads.6>)a<j43`5&EYp%rupk6.2ea3q=RAYnI6L,aTZ'$)$mv#RF]*+0Ouh%paj-*sVO;7bp]dk^-e##Xww+222K`E;NHD*TM.Q-Diem-PStZg\"\n    \"#xUj1Mnpr6WO8I*+DWD#x1f]4v+h.*bi.$pFon$$N)pP'M<D^#D+#NB[MK/)9wJT.scR]4;sHx-2LqhL$,vX$n;jv#)_$`Ksa^H<eC%p.dqk9/p3=c/aIUv.Z_06Aw=871EQn`*<Qj_$\"\n    \"i-CV&N_^;9[V,7$g6tmL.,oT0nX&ndRWc9%_1e`aZWD'8,B@60m^&2%d%04;km>aEdhFX.m>:S?F?,P3r'`s-)(S;-NkhF*DgU>$(RhV%17(V&sdeKWQx1v-QqpA$wJjv#@RAGV5T'_m\"\n    \"S1D;.St^a#xF7.3>8N1BY?xw#qbD?8%?&'$?fG^GSv.Z,Rw6c*e2_V.T<t=/%(IM0-&P:v[$m3%A*&#Gm=hG+d[lr-x5^f1w:ZrH`';H*$&qo.h^HD*tBro.53,H2(g/+*P&ID*B`Lv#\"\n    \"2]+>%2*uU%UIF<%atr?#;69[#u8rk'ZY?C#Zb@W$Lq'02tTI5/[mLT/df_a4As(Y$9nLhLKLL+*hG+G4YHIf3Anf*%uWTM'':p6*.Ex>#tJUJiIWlf(VrapurH@hrI[TV6'GMO#$I+,D\"\n    \"$X<)<hj*S7hb8au1w[t'AlcXlVF)[u..iW)Ir:,%/PcY#re9.)bC'5oEr^B%[qcR$u6tP]E7E`#rqBH#)Wj5Ac*od#9*Lj$kwF#%2reYKWBj)%/atV$HS[crL8wH)DB/?#gCjpuTlgEi\"\n    \",r+U#n*0ul^)&Bd[hiqp6(Kq%QGE$%8laS#Rosk]P%>t#hS2J_jnA-o)oIE$09[Jk0X7g2]6u+`x,4lVnmVs#sS+U$@O%<$PTx>#gCoJ1dX)MgddaL#pHPYuFseV6QQmPJXB;#5ogMMK\"\n    \"`)^I$&qE.$tFrg$,+1^4Zu^##h0IP/#$&##4Fo$$%D:s-HK#w-du_8.Zqb%$+mGs-Xn`7Bfc5g)4q<j&&tFA#69xU7Y,i(&V2oo[#wYe<];H`,8qq02]Ugx$KO&%-mM2a#MI0`ZZ4nvL\"\n    \",+flJW86?A9Gw;8&HAB$:3]vA,Y<X(5p;Q/A-x4CV.,@$w>d7&wK7X-V>hQClKc9B9MwpE,D`OEMcA`<:QA$l`#&Z$gak8Ag_KO'VF72L*o''#'/###6HK-m8o`i0;;OcD83LG)QNv)4\"\n    \"+gB.*%>M>$,b&e3KDWD#b;,x6@E4v-FBo$P]=OfM9;0r-L3sO<Zn`;$]?(6/Ofg32THtD<gQYI8p)@M1awf8%`#(C,d>YB,DMw_#Wg#nA,7EbN%sCm&kk@wu?4H^t+e0s.^bO-)fDQBo\"\n    \"$Z*tq2XT0.OtdP;_Tm6D]CP2EsF?v,&7GgLo7wR&T_S2',964'_The$^Fu,Mm:#gL)s24'2w/D6)GY##Vs=b%S6[0#^?O&#@Vs)#?;L/#0R5l1q8^S%-j/+*Vrw_#PDRv$+G[C#+87<.\"\n    \"XxMu$$HSF4YS>*(x8eH+Uf-]-]iRn3LiM(&AD@T%>dY=$Y$pd<XKbb+#roQ0Kx&x$=Z/k(P(7##D;2U`DIDO$[6<r73Y;h)^_6)(_$8[#C^>CFtKU'#d:0cV<N<T'cu3GMPKF]unv%?A\"\n    \"ogPI8XXo7L/wDA$lp#r%lbP$,/B`NE:l?87Uf)gMhSUq2axCj(bX@k=A_C-MTEXP&2HN,<5Rt>RsP6i$O?&##jn-N)5a'##akh8.lEZd3`m#`,EKU&$V#QA#&XH&%H0LgE:kkD#7%x[-\"\n    \"?;'lURK*785>>)4u<fc(E&F@?$fH?$MBg_u:&Zw78Wc`OgviK2i#h&tAj*.)Nbwp(<19h(owp`$e4D<'W2.?8Rms;ANkREL+nK9(k3qZ`c^xb-a[s5:&m.38IPQfr4o+&uHW9@M#^8+M\"\n    \"r43n%th,nALlR,9eQD8A-U,h1IXI%#qrgo.2;XQ'D]OjLsIf)*noL^#*8@v$j&G&#=TokVq6$4(Zl(?-6p%,rx0-^8SN3e8II4+EC'>MK/1ELlS]kUlF3x=lUPV1^EOT1^r`VGZj.K(U\"\n    \"IXBe=IM,qe`9QJ[mttr62u):/CS>oRS$L?OKY5<-WG@^$Yoqr$3.`$#Kp/kL:<().)SIXHq&:B#pe4`#^/6c%dTqc)>M3F3n>j.3[Cl;-Zfv@-^]X`EEarsPUSV1^i8S1^a,d%.<>g;D\"\n    \"&wfsR0oDL#XQRWY-<Wv$_]>[03&l#MlJRiP;B+OMtRH.:FtqWDx*L^unv,4fm.N<LJOV72Ks0&=#?'$-,5R]4i:gl8+'`a4F.@x6M]]iLam5;-pNR=-Y5w*3P#8T/Ift/M_/YF3^V3C>\"\n    \"c[M?d;r4PPc,av@Hl:.=OJQ#aH`kFV:bFW-mVHWUupW+MdT]BK'Q)h'e8OwgN2:[jE^w#NAuB3K$]9X1fArJDRYd*NR9IXl`YmW#=_'wK[%N,qFmNfLv<5,MTpQ##:hFJ(`U18.F(bj;\"\n    \"C%=+33wjW-F%uH=kG&J3,fj%AKkK,3:&vp%1>Of<+Fk+=qN'7aG@ZR#*v0,)K*:[.^DL'ucu%?A.cwp(h_=h(%&(<AQ5-h>vfJ:C,$5F5T(_Z`q-PwM%75mA4YN-)Y2VVtQK%Z$@@*9.\"\n    \"4mQS%a5]v5Qqn%#42<)#uH`,#S;L/#1U5l1q9Ms-'F/[#@>(H3Gqf79,]@<Ah(v59<o,K)fK.29p'lA#u34,%&4u]>Mg$9.-4Mt-:`O5_N*-$.II&C#eVR5LkKb.GJx^r((wDT'Wk.[#\"\n    \"`is]unSMZu6TBj(s7s9)iAO03jrDO'h6G(/vWxE%=%q&tC3[;%F_K-2Ra^)?^+h/3Eu?c4c*-DWD_C&G%8&Hk[aTM'H$M(&:7uA#T4`3OHvxp7vlKE>gc8f3W$J.*2]r_,*d5M*Vxkd=\"\n    \".:#gL<=*hD&@lD4n,&'HTK*782x>-3QkcE7&d=81PiG=&`Kqu.[l0,)@vDaGaoj;&fJIi;2<7Q:*/BfhEn$SVG=X1:`7UiqD5Y'Oc)]O]$-lbVfl=03w[s`##&5>#MNa##)ibo74e4/(\"\n    \"ml:^#483F3jX4@$Ak3Q/*^B.*ODDD3nFL8.Gq[P/=J-W.`?7f3^2.WI%GxJLKKOA#n$(A$,roXkCtB(;vqlD4NB)k15<d*Z+fTW8#@M,$/YeEPE_(a@TIUNE%Nh=khV(V#;dq]o'VTlV\"\n    \"uEHd5=Wi1pG==>5V^BxbZ8;rd73cS92IZ3B;f?$Si.Ic<Tm*</h[Nc+6R920N]oi07)C*P#^=7aD#jX9a()q'tg[$&o.Q3#r8q'#'PC7#jBUhL>$<9/h]Rm-DSR6WkN)8_wq'F*sAL>$\"\n    \"b_4<%)%x[---`G),vXa*M?=W-U+Nq2?CR)4`]3-,'rXI)^`WI)<%M,3UWkV.ikkj1uL]#%h.<9/GdE.3>?>H*8jhD3.j$A-T@Mt-CC#RA'Y:a4w($lLokkj10WpoLPNo.*dK]@#ucS@#\"\n    \"_*@HlbA*A/MwwSB$6-63M?.P'/AX87'o8:dNpxA,Koq7/[V)Y?m*F9%`CCkL'GNX(x#sH**453''Si;$MQ;E4qDcB,hbfM'#cj:I%4rT9Ph``+#AL@6wl,',D%Vv#R#`K(3&do/(9$6:\"\n    \"lXOWOiK.+>Vk_]5]WVE0R_me#cpPR&OpAO9qQ,w&lRhX-_K[K#udjL#iZ)F3+2Z_+8O8(d-YafgC+ZA+4UpnJRjAE+00AjKXRpwBd@A7&i<AN0%?2L;?-Cm&:fYC+s6wo'NRl@5.Y(Z#\"\n    \"*9bv68tGv.XBxK)BQ10(@,OIJXI-lE-uc70#Lgm&Ef<F3g71N2xm@X-vO,$,gt@P)3?0UNm'cS--qG&-2A'e=CxQJ1ZSICI`n(o&iv#r%/$j=M3bk`0&q.w5`^''#<C9C4`hSM'Z)YA#\"\n    \"2nL+*ej^)3;#K+*S$2&(Lw'&X]LB?-Hwlf)+_6r#K9F9%IRR9(H1v-laehePr^=muSr]0'QI%2^+.<Zum&v(+_WMP8H_a5&Q@EA*WWQ^#DXCw-_h-*M;#sr$#&5>#0O*N0O3=&#0WH(#\"\n    \"nuclLmM6&%sR+F3kSID*ra-<Ik[HS'dL0+*pr9M)#dq%4)]Fb3Or'f)s@be)R,B,M.:'/L@%@Y9_(SS9QIolL)h+s8PU_,`U.8q$S&Z_&`,Y[Ml<:+G/_>5CoZ31uN3iE6'9i$$@5r*3\"\n    \"*GP-NneY?`[sT@tFXfa^I'$AM:A3Y5^CQ=L*0FcM1rFS72>>^#S?S2`5&I]O*Co0.8<=78dKo`OU6OI3sE]T.Gqn%#3%[6%dx.H<KnwVo3+xRV8Q'Q.#f-JGtLR`2jda$#*f?8%T6###\"\n    \"x8q'#BDW)#cO>+#-[%-#Mgb.#nrH0#8(02#X3m3#N`aI)m8Hw$#3hf1O@7<.rM[L(sl>x6K]B.*Hq_F*/p^I*IP(o2s0;s-6I7lL*8T;-,fG<-JEVIM-7Ms-vlhQSZ*kJN]eC)NF.AT%\"\n    \"A(OE&o(ID&N5t=&`[d3)w)a3EaYs%=>=w3EV%d>f>O2O+qn]:/OYDB#s@M)Eq;+Au&]kA#[BbY$7+CO+sgU%0S'CXOS=lCN1dh@-%NOgMU9f8%m1vQN+XPG+HU`]n$Ck8E$DP##%(Y4=\"\n    \"YJHB,O?:6&0-_k43qxf$_SA[Bg(nVQwi3RQpYIm-2%s@0nPHJ(#&5>#0GY##ftho.05r%4PK%29Cwo1K6[$>PVr-JUw27VZAI@c`>w)##TpB:%6vGT.:2Cv-XIV9.27.##c5h<-v_Cq7\"\n    \"`9cD4t0`EN(t&4MJoor/u3YD#')'J3[;dX$,N.)*aHX,2nb:H4B&B.*6%tx9lsXS*PA5#%D=HO'nI$:7Nmjo7nChT7qs<h#NPbi((glOMPC$LMf*VPO;FDX-sQ4_Z$MEO'F:ikE/@3=0\"\n    \"$XSN0T@8ucFci-*<6gr.1aW_$wN;$u<jeA-)m;eM4DA`aqlFMbdDDO'4$HCFt7oL(iK=raGmKwTeOrEO/j_*PI*8c;s8h^#HZr8<G`CAP7(r?HN1r-4`t;@#7vKC-Sk;eMm?U'#'>cuu\"\n    \"#`$s$1fl##qOj)#2#(/#?3B:%V(l;-i.<9/X5dA#D.[s$<n3iMBIk'4/B)<%b(K+*:0ihLvxPA#(@*Q/6$d]4q:8Y.UPJ)*<qiP%17UhL2ak/MXfZx6gG7l1P8'gLX^Ma-=Y.R3<-+mL\"\n    \":_On,qoPc(p?A[ungIx,Mj-o#d0%biA=@8%-DP>#CT_b^s(t)K^ROH#:s:I%,GY>#=boi'r'e1JikMPa[VRoW^&1CMB%Dt_;r5R#B7O^%RsvD*[I7;8V-RoM><HQ88EEa*B'9U%H95v#\"\n    \"D@oHQ]S6;?#N7eBhr'6i=';P#:Wc1K<r/q%?M4m',tuF#oAVQ#`EB9%MbTJKO&DZ<]@pb*qM1q%Mo<ck7`H1QfdMIJ#EDxfQ<i/MaSD2Mt7tVh-l&6&>3:6&Xc4fFZp+k's'I,YGF/30\"\n    \"oOes$IJ49MG's8%HebY#NV%JLZr@/L9-(,)j,KZ-1rt^.YF-##$df=#t?r5%HP]^$ZTn8L28alA>sK<-jHg?._-ki'M00LadW><%:-n%leQO8Ac>^;-OLM*%+@P'AY5>##U^''#_>QJ(\"\n    \"+f?X-Z]B.*AfmR<,xTN(7%x[-DYSfLr+$>#8v-./oi;?8NlW<UC80FAnsKW$^j5?AJC1_ALDuu#jnt3+uue+M8+(`$44cA#UwE8AQ]`ktFZ:D3bhIa4i:AC#Kbu8/'cQP/*@dv$_q@8%\"\n    \":&m,*WcJD*te9[('=],RaP12o)ceD&=P#<-T$R#PtMpuGvB%dMXC,hS')@]-$)Fd==7(p7`:T;.5bDa*m'`^>;8h>$)U:d-GLrQW3-2F%EPTx':c5q79)lA#ld$eNNtL4fmwx&$AU629\"\n    \":J6$$6]###OKkA#*&Rn/-E$Cui,^m$QNg%)_JOe##N3T#Y5w>)*7,F@OMY##^*pE@scc&#Ai8*#j*b9#X4OQ':t-u6Q4Ls-1m+c4dbL+*[t[s$8;f`*erUs-T+2EOMkGQ'%c7C#;)^F*\"\n    \"W@i?#GCS_#BgS=%-@XA#kntD#=PsD#3cNT/CCh0,.TID*Jj:9/u`$w-'7b;7YCv?05HvA4PuOn*K&>m'H<3B/M@[s$]I?lLb%S_#Jo`D31D^+4maihL/B)m0&HT7/s,I)*CNNl(S9Hb%\"\n    \"p]Ol(ib2[5rX+q&+nZ4(F66E*AU*9%=P.gU-;o5'<C_dMFT_8M5OP,MR-PQ#E@rP4qd&g:.2a^#Y6tt$<fLv#^RbD*>nEm/S8IO0bC_S.0S:v#AKl5&5^nfE3C7T.NE7_>DsN5(GQ70)\"\n    \"#eP3'CHD7'/](?#@1_+*DL3Z-E_+@#ai<e)?%A3:b+1<-F>Yf*s/mN'p=)-ERD.5'iU5,*gt7[#h`7)*2>NO'7lt^cr`i%IA9VRDekQtPqW4mu[-cAq2.xW#4gkI#4W#T.*@$k(24I2h\"\n    \"Q2n)*k/-.*^QQ3'08f5'0FaQ/LKC8Ms[rS%7G0u?&3#',=^UP)'Zrc)^]ed)ubgb*f0D@,At`j9-[pQ&*x/O1u8C6&j@0(>B:$E36b;q:WVkS7O-qo)t-mC+tP9(,1h(E<d>8#,Q12S'\"\n    \";9X72s]2':]/%h(HFgL(>Mm]#8r_V$?f(?#X^m)4@<#FHwQSs$p@L<7W6Ya,Th.],wlq?-PT>Q#@Q*oKb,Tf=Mv^oIv[rt-$*5>>t*(m9I`ZO(ZK(E#MV&E#:13:.KkRP/vD83%_9qfL\"\n    \"n<<Z#+kRP/L/I&4&,]]4@6*I-^A%&4^Pob4B4r?#oNg;Q:5Rv$D9H$]4pWQ1vsJX'i;rl'A#=cu#UuG#p2_[6lZ7k(ixsD3)SLd1.h&iuJIjj2:[jP&nsepK^Pl(a[Jk/(T/.E-2j2Eu\"\n    \"0W4X$2)LJ#0PuY#&P2iux.4(LM_]S%:$?4;s;,S/4_m0/bf.^$G_hgC[^[b4<3arQ:j)7't>s^+u<B^@JCuV(?%[X$RUZ##e?KJ(*Z>G2dFeu>[QXoI9<hc)`3f<$R>q_,HU`V$4X-_#\"\n    \"ax;9/+r,s6G?UU)Xax9.][rS%C)MT/F$nO(,^YX$]1O[$?G._#=Qd*3ub4V/bR0]$=oCkLe;[&4v@v`4t/eU%lYL>#@6>N'K0'U%hM7;64LsP&=+i;$5+7W$9uLv#$P_LJgng;ET_vn&\"\n    \"Q'*L;SOXi$i6.=-2oOe)/]1Z#a2cAYa;G>#@iHt-X6YYH;B3/23k3HA3:^T%GG9f^U&v/(6VY>#fuhv#]6rkBhO#V%Kq/6&'Q<9%?+iv#=h/Q&&HaW#$v^B#c(1Z:g@['5+n:87F_T1(\"\n    \"^tnW$A/%F3s@PF*MmNL,BqIt-X%t^,D;*g(;EhT%(3###[,m&4@[jl&RM<A+Yox=PNCZ5/N'oP/1tA%#k17C#a4n8%Ykn8%qP``3=V$<.V:[s$5_6v,L$S8%aCI8%q%K+*NY&E#:&^F*\"\n    \"K47W$F;]iLZXp_4x@Jn3$/]fLS-+Q/mMG&#<V6<.6deiLHln$$Y)BkL.dRD*B@Fp%cIuD#do.?$gK4=$-u]2'[HfbH4fqE8(bg4A^LC#$P-TZ$mV]21dYW'KuTMCVkNtBE3C@GX>t2q/\"\n    \"$L8<$j+_YWLB7j'H=Q2t__hs.%N(>$6O5pu3&RE00ij^/l6'jb/EiB+IYL^2ch5^.,.Qrue?'s$2cD]-l(Rn960)#$6Ikr/Au<x-wE`JWoZY^=%Dt(4i5iiU,A<>5?^%VcMlFZ,M3&2?\"\n    \"s3cpuS76),=sb+4GlXa#l*[o1#8=tVEOMHK8?dlC^G2u$H8A>,-3UQ&Y/CC6<@Kt5.?cs8nsTq%t;$k*m0G=$o2a#8x)T7/ZrQK#';VtfMxoc-Ut%w#7Y;2'5dUK83FU</?hG[0t/%l'\"\n    \"6XM`+?qH>6oWnMPiGquBf,5h:G($(HiN%##'&P:v>pHk$:[I%#>Pj)#=aX.#+on:/*@&s$^4^F*#o$],pJUM'&SNj1FPYx6(.uA+U=US.VP/H)rt-'9/K5g1@<Qn*igQD*8ooA$3ec)<\"\n    \"^rd(#ex;9/5kpM'otS&$OGcl9K>YXCt3e9.Y(ic+,4Ft.hgpQ&)QYl3o#C+rnt,0^Jloi'5&`D3)Sxx=5$lr?LX`+r52I*g?],lMNCCJ#gT]ru0>eou_;8i^s(k[$H9wQlgSqLf[Y?A6\"\n    \"TM.wsIvMA+]85%BE9raQa=57`p)g.q[6UV/1(6G*9iU;$o33q.aJCZ-GAg=u5vjEB^G6na_dTC0)?v>'#HEhukE^dVI>]<$)ug>a08^IOWkf87FFj)C%KB;s0xYxVo,%hgascH*n8;53\"\n    \"'$^TrqIo^$3,2X@mHDgf#`3d#^iX`fXIVS%TD###Tx^##8Ufi'r)#,2]V5D<G.H]F2[ZuPs2n7[KSae)QXkD#X8Pd3t<7f3E6o<-6Sps&<H^@#Qc^KMaPsI3QNCD3Xq)((3G.;(=wNh#\"\n    \"Yo.I%?PY551d@+0j.8$$pL=D#':MLMGG-##)Fi0(qOX]X>xhQtadO&5@pFnEw@b,M@V3B-/O$<-)Laf1wo=:vUPvv$_2B2#PJZ5Jn)B02W#:u$CO.p.QDnB42`&02Sg'u$TekD#hHff1\"\n    \"EK(E#j1ffLEb'E#SJn/1c:pr6nsoJ1R=h8.p#]JM(dYA#hMg.*djuJ(B2Q,*EdPg$UsZ]4,:OA#JEPJ(E1tD#+HZ]4VrH,*RQ1OFbf)T/&Jqo.Zg-W%`gdvXe.Q3'5-gh_6Pwn92.#fq\"\n    \"t:n`*CJH$GjEg&G@?3d*Z44pu%+)k9T)3l_2/[3'T],qX8$BN0#v)D#xvisul[S^+)lC`++btD+;gtw9<T0tQFkpi'MGac+)F7a+OOO7e$7xi'LFNP0@:+DWE-_E3YrDd%*,7F/1*:B#\"\n    \"^UX:dnrB$-&.c0La[29/QQLt(2>`P0_QC>5dsO0/'J+KV-Jp83;)PEERIp02&8^PU$,WS.Wb>,MvtCR'#X5[.?^'O#_36[.26'O#Iq5[.MF3X.jQ5[.RB_k1Qi=4%mg88%)5###[^''#\"\n    \"3bGl1+RPQ'Pl4Z,w2kU.Ua-)*Do:Z#4`l>#d^*G4ro+G4kSjL%L<SmH-T2uD@mq&4]7qN#,_ii9c-J&JC3Gmupts@+eaX_&9OkQ^k92k#uVQ$W:%X)<'X[SMQ8AaNefwV6;'RfuKfUmu\"\n    \"QkkIMJPbJ#f#%R#R0e+*9P0k$lv<9&CEcf(U3]?T:r$##f=8T&,aKR/$G)?#YD-C#8sus.#og>$d:H)%+2t**bXe/;MHh)3]=bU3dOCU]7u='*CYHG2wjWT#F0=tpa_TU=HR'sJ)[gqu\"\n    \"B+*+hFHoT#0PsD#R6Na;*[:'u9R05A<AhrHd8l33V6r?9XtU8D%VK/=lP0QMNUJ,O]s18IHqKU%K)9xtaP%?5/H(;?GrK`Ero2JL1JGi^_VIoe6jg:m#_A-m`weP/ZESP/P[lm'W=1s-\"\n    \"R]jj1'`wv$iLffL@O[m/6Vo_4%[*G4D9P)3fd5N'G#[)*&R:a#/lF+3#fPM9NP1E4Jtn8%Y.<u.$I-)*j5Yb%j9KM'VUIs-*9..M8c7C#2,h.*V:j63f8k*.%KET/la<c4)8r&MwI_F*\"\n    \",%S8%JVu>#W7PU2//4C&4XO[9HUatCxvmS/ZGRq;^qwX$FwUe3OOeG;=+@-Dv[Dv#64R8%5f:v#HkaT%^x4Z,ta5/(XdgQ&a43-EL%/u.QsvU9.K1:%3qOv,TU;Z#knpD3*hp]=Mmje)\"\n    \"qc`iKD0vh2K$w03xIe/(]TXx#TdX]#ZPUs-;xXgLcP`(*fj*D++_ChLr'#^$)J/$5](q^+Ju,@97dE/F?5Bh673hQrHgh]=)ekv6@.J.EXK$:VB'*hN*+vw$(BK=-S$Fq%3OC7'2#Wm/\"\n    \"^&et-YBC,)e#:>$KeWI)vxRd)km4AuvVP$,Fxj0(SN:a#ApLk'jphtLe+n'(9(TC4W*V*4)IuI)0]e.2qdHNC9II[#*AY>#X:Mo%-oa5&2PY>#P<f@#HC%[#`f.h(%Gv@PwM129R'NA+\"\n    \"ssFVHK-b9%_CG-r;E<H*D%Y=Vq-75/HTV=,34Kr%P,o%Y[U?x/s;XCj(#.V%oe%T%/[wF4?b?U7w`%h(Q#/#,&/0$5C?mn&+3*fuVM`&$dO,^4LjrQ1>O4W'UWbk5X^^i=9vZK582M:%\"\n    \"?[aX:MW-6D0The2.s;bMoX;I.mGIL('XV@$-6fM)cZ-d)wwi;$nJrh+9mln%/Oeu6RBg=>RLDv#l=pB+r3fZl9YNk'Zew@-//5##6UEt$ZN*1#dBV,#3.i?#0ljj1ilMG)ulnD*ZK(E#\"\n    \"#Px+MFT+Q/F.@x6H%AA4APfD*mPwh(uX<9/#Cs?#4's<%-A*F3#dE.3T9@+4;h$@'bn`]k9@vAgfs`C0viOv,pg9c5H@w(/3kXK16jqMd`]2(6me`Z#D-?-3DdQ3'=B?c$BXkF&YUhJ3\"\n    \"S^Z/9L=2C8@30NMvJi&Z7Tb(K?()>YIYu'+KZ5r%6>V11cf8P'=-uf(rYG+%jZX5&[f>B?1<GpN/Pde:&S.42HewG;$qCC$5BCdYmPWkoVv[RCi)#O<F.]%=C)v9VjLKtM)<&##u%KV-\"\n    \"/4w.13-3)#Z7p*#w,>>#[rb;%RLe=-'scT%p,Qv$j99%'nEkc%DG+(fZW2?%.t[XJ1cpP'H=AN0b7RW8'J,5A>Q?KN>Kd^$lEVP-'A^8%V6ar7<olHNgc6?$u-b_=i>t@U'UP5&RJ@,9\"\n    \"32Af$tr[fLp%:e$Mw60#vsboL:;x/3Xpb]#[BFA#6+[8%N<Tv-T8QW.aY8f3hii`35&L8.Z5L>$(cK+*OV>c4(e*G4&k`[,:=@8%*mLT/@Q><.d>l'&p@#s6L*H1gU,@T#VH^=cB7h?-\"\n    \"+u@T%;:/?#Q/cHoKEU#.Q-(O1dORW$dXb[$6uWN1E7;W-Q_e>#4(r;$=_J8%'@c#%J0%f33c1Z#.l$W$b+pFVPXL;$OP-DacVbD(+MuY#EZNM9,jOU%8_uAofG:burw2`u&+q32c@6c4\"\n    \"p%:s-cC?42wh<Ftpf_*a)xlH6g%j50OD?g@dNgk/f-$-3nc>j5#7>##v(1r$p5###*AP##<hFJ(.]3DW$d6DW645F%X2t&%`=a`uY;D:Od*%##xuF:v2$N[$.'*)#WP6C#aGUv-7J-W.\"\n    \"?7GiEhx+G4inL+*1oA[[.wdG*;w_-M&nr-*S*TM'Eg$H)lp0u$puU#$Uo2L+s;>YuQ+,Yu'94)S6Ku]4U?[(swLcY#Q*RKupZZfC37n8%Z`-jo[sD>,>b.4q>$1YuivF/(aDGjCZMep#\"\n    \"3`,L&p5=VZ'vAA=&<,>uh2af3UiU:mr'JYu2j86&f54]%rc&Z#8(F?%g?-/q9MLm'^FJ?pn)g;-,fB@%,R;8.6<Xq.4n@X-'K+P(;a6OG[51SVf84`3pYV]k2w3A##gD]+*(iYJ(VIeG\"\n    \"-QU.ufsH#5c;+VQD?EYumI?AKZZ>3@M05##(S_V$u0hw/q3n0#4=K,3Hl0[/cR*X$x'P#%okn9%n:i?#t7^Y,Y]wD*2oS&$sX#`4`3f<$Y$*W6[t@`,u,pf1T?5V/a4[s$gP]#,YLU8.\"\n    \"CLD8..gds(UsK#$F/lv6@f6<.=S]=@IJD&I1JjoMG5R>-sNfZ7xPmAu:ukU%gZ/N,T8Y?,93S>#5pTnLrwAO25t.?36DW5&pauV/#,801+w_h;rei;$@`0H2HE4?#RgcT%Q'J[#eK(TR\"\n    \"s4x-)$ucc*OgH*3MUUf)X:;?#Pggq%5iqV$x[-,u2d6w9,j?f*5>cY#X2FZ6w?nnKF36C@iF@,DUD[e2kY$'=u%MNE8B6K1dGUm2d2eS%v.oL(ON+vGn=<L3S,j]+@/Ek'jl03C[e^Q*\"\n    \"d*B<$YFsx-_Mig(G9G/(UE;.3uHYN'w-%t-;'(>$%####.IPh%&818.T&t+;>_Za*nA.K18+7s$$]K+*f5xb4I^4L#CD,c4S?]s$BQwb4(MHW-(_m3+'IA8%q[k/%5&_s$Mw60)r#+/h\"\n    \"Ni*&75+(a>Rq(rV.X[h(7-$(-d<Xt$ck,AOLqGV/lZRX.aBo]6Y$e(+t3D`+vN$r/oeG(+S&>',MI/Z$0%Uct:Hbc>6_M[%6],A+Vc.o0OU_/)kI`S%RsLK(RialAAxl>u.f^&+.]Ht7\"\n    \"]?_U/X&_V.BL%L2O3a%,Erc>#]Suu#MY.JLPF/mJ`*EM0^'%##4:n8%W3D*15g(T/kZ*G4Jwt(3EAd,*GHVhL$Q`iL3?M8.>/>u-Dvuan)>_'/a(t;H2cBo$:h86&UeTK2Oo@a5XaH9e\"\n    \"4Hb,8wW[0)1vhp/g(/?AICc4:TlIZ54g5bF-),g3r*HI)7S*mJkOY%,l8QR&i&1S,3%BQ:dXGbu5$Ff2n/v89KUM<9l+'t%VX`D<;O%Zu25K+*3L,s8s1/(#[^417eX$k$M,85#1^;W#\"\n    \"a>-C#NF<L#$a;W#Ia9^#M6Zu8cJE/2bm%gLfw;9/OB3j1%S#<-2%Uo-&VE_&CI;8.^?m8/*(R1MdbQLMkYgW$Rx]_4`-Jb.x-kv6ih^F*$(C9r?2'J3KU%],7'A,M7ocW-Aw-L,>P,G4\"\n    \"7=Nb7&hWp7EulG*J4pGM.qugLbW,<-S4PDNVPI?8W,VT/mKd12ebXcMB_u]#w-ikLqHZh-5^Oe-;;Rv$Yp@v$nNTm/o8ZZ$&R:a#;OTC-P>AYgTGC@-^DSb-&)=hY@c^N2HxNj.+#Vv-\"\n    \"'G1p$MXp+Md;T;-I^Ma-nGKb.2R[LM2pVE-sKX(M1PPA#28GjL;_W#.2f'dM:I8f3dS>d3Td/KM&Bo8%Jx(Q'%/NbMo.L+*7jXj;YJ+kLxU@C#L`oS/C1T;.*H&<%+RG,M7YjY.l[KF*\"\n    \"^[=SM7b2E4$OnF46Y&_o^0ZwTX#?th6Z)NM:?/?Mdw;9/]K=b72_Tu.R]jj1%#Qt$gIc;%?+i;-8xr*/W<7f3ci1I$u2K.6<%p+M3>3L?1Mmv$^NT:%_Mox%PTx_#Jt;<'BR*9%6]6[J\"\n    \"c#HR&7Wpa<0Aw$$^HtT%7eLa4k>[8%u4''+bZ53'QskV-f/M0(2$B30>efM'3_/7/'Ll#%>k86&SuM_=`6xs$^/s[?81L+*1j#I>uJ%L(uRKF*kWPj'YK=t$[2Qn&bAe`*W<cJ(1csk'\"\n    \"h,q2'o@pF*7[/Q&0@hn'I3>N'?o:v#6;7i1l1FZ%6PvW.fBqQ&eEuT/(knT.NLTc35t_0(XH<L#FbaP&maju-Wp'M:Pb^v+QX*p%E8R21T?>,,Fh0)3>uH8%LUKl'IvA]X_4gd)f'sm/\"\n    \"vX<e+K72?#DQcN'oWpM'8u$<$DU^Q*5b.F+@mS0)[.Z>#lCpl8QV3*6$urv#0PcY#Q'g2'#O'g(JeAQ&]g,11UdGN',n,wHUGG>#W`N**FriH2<Heb4wKJ<$;ggI;U;kW@a,ikDp>Rh(\"\n    \"1AI21^[2%,E9IW&>uq;$Oe3T%,sH.259jOf0+wo%kxV8&pEKP:wCa=.2iU;$b#dN'XbHP(q]w)*?p6`#Z:lZ,T5E&+;.%s$69PY>4w<**5tbq?'>)v#-]_V$3Qj)+=PxfLs2J='Yts5&\"\n    \"jL#(+)mOD+?=nS%mtG)4*5,]#KMjE*N6,3'QoLv#E0kT%MHB#$RtRs$CXI<$U$'m&T_*9%KIrZ#J-Gj'&4li(Tcf.&3'JA,AC7<$Xm'u$b.xP'IK*%,@_Fo&JZ57&_.%O=CX(_$At4/(\"\n    \"W*lDjOU[8%sk5;%BX[W$WoY=7v;#s.qjgD3*Y8=%WLRt743^b*:9#T%pPlA#[8RH)%aM/DXn<T%h=]5'G1:8'ip06&&0^a%%lXF-XLRW$KEKU%_^>N'`ojE*jkP2(@tQg)PeWT%CFVv#\"\n    \"lpS@#:F[s$_;`0(7Rap%0c_;$>BB;._gFx#'c4^.Z-=T%t*P6'UIE9/awi?#/Lwp.U-;V&p$>Y%lp&s$8fP>#wjaU._rND#nHhiBK'1I,7#si:pK(U%l)T&6-PBPs#'*a*0]oa=Mh`u3\"\n    \"]%X.)=Ax;6r8qH2JUV?#%EFF+kDHW.9LZ?,>:es$M8)6=mX/H<?N+<$aZ4X$VW':%RH_G)w5_:%'-';.A*B[#[5'g:MYq<-;q^=$CLiV$6+@s$9VrY$J.tT/pGCn/233>PRd5R&9llY#\"\n    \"IgH)*x,o(+$;Wf+cq_%,@Blj';C3T%b=Vo(aQBq%0MtE*1]b+3-wa)%2@G-3*+4X.[P2N*9Sc>#AZ-d)JB^30AQMK(SZgq%E&:G5hAwD*>q0</l6OA-0/[9%vCaw$]99q%N>P>#,TQa3\"\n    \"#80+*lS?r%-chV$_u&F*gAbD+hYwH)xdgq%jfFx#9_l;HDlL;$RXns$CLV?#m[hx,&49Q&3+/C#qG/#6]ohV$61[S%647<$PBgQ&X5`N$PQ-)*(Kn-38X#j'L^q,)(5Q:A1YAx$rP?I2\"\n    \"@1EO)cx?s$&?Ji)ou1@,)V$##%&>uu+H/]$=EW)#w,>>#xk$],:8,d$m0^M'Rf]Y,X#:u$YKVT/kZ*G4QOTfL:=o$$/,-J*6*YA#[j:9/%IuD#,iM2g&F9a#@a2@$s^0#$%rP29TK;p&\"\n    \";clY#6PAIag1YS&<+wo%U:q^+w_b4UYx?j)e3ZCHbM02F`QuW[o_jP2/;d[&RmU0(Q'-Tq%$Jm%TLd?6pwva5K+hq#E$K2'VH(D-g3=)+n'p;8I9gF%^p&X7dOLW-$]QLM5449/Ar?4)\"\n    \">&E@.T;.*3KjtSKv*Im00F9u.IHWb4u`rK*4q=I%`OHYu$#Dp/K%Mb$J/Ri;KYqr$LV.JL$qK2K-l68%=wfi'ZLLS.ESXV-2j'.$3ctM(6QK/)HY2-*baGj'Dck/M#Z`G#NNg@#Gw,ru\"\n    \"tM?C#vi`4uPY8a#=<5/$9drx=`AfuPMeqF*h)w`$Fe7[#Ymg>&6trRR<%P+D$b``E$$SxF%.r._QU+Mp4vug1D8>j)WU)?#Ucc##&16$$--W1^()5>ufv/Q'JxtKPPe_F*0K'b%5pXV-\"\n    \"*$SX-ai?<.5DZP&W,L@#Tf@-)jJ-K#FVDqK6aG5uSmv3)Sh@f1S2L)/[m'?-i_=Iuq?sReNA7eOk>Yt$km2<#>g7-#M(wr:]ZW/2iq[0>+VFb35s*Q'?[e<$rfeD*k=8C#+&^F*cn%nL\"\n    \"bf+G43HkQ',I6u6Ei``3R2NFMOk?Z,k375/DIVs-@Cr?#H;j%$1E.H)QNv)46RL,3%>8T%PhvlSUB$=E1Q0Y,DKxe#,;J_4'fAZ$Gd/a+CWe'5J$kD+h.oN'A.M;$jg&v-3/1mE^Dke3\"\n    \"nt$M3.mdd5%a8B+3WQ3'p94Z-JC]4*COb.?AvAQA>oDW-(m[8/.Y8l:HbZfCPB1l:)6iloW;h'j:46OW+7HDW?ZxFDeQs6/-AM)F;$+`$M5>^,(@>m'-Ukt$2GlY#[4K'+f>H7&&s;W%\"\n    \"wP0k9:lMT/1HbhW1tf(+*xmY#:Tal(?]%7&iTXg1GXHu63k*S5=YU`5:Al(59Waf<VMaj$w;J`E?5CG`5ZViB:j&##Jqi?#K^<c4N5TF4enL+*>'oP/X52#$rS.d)c[m5/v*H87_L4gL\"\n    \"=u;9/$$(<-FE#w-vTK>$sim$$q;>x6Nnpr6<jft-1]WF3LDpF447ST%Aw5,2jR@/.6]p-WnfEX$fK4^`e3XS9C92:%Z54`HftDr7@a;g(Jd65=Ug7C>7eFT%%VkSC;WbPD8@fS%O76p.\"\n    \"3:TK2NL7/=W#$9'r1Pc4HW?%HV/VR/i3#f4VtI>#J/JT%S/1C(%#u%,G)Ft&`4'F*rUoN0N=ce)0Cu@51MceWF&8a%6grO1I#jR'R@gp&M`q7/01lM(#FS@#CZH)*0G;t.xOU+$*/:2)\"\n    \"Y_qK^*<jp/0%j?#]WI]IH[SA6ar7T%3K^Y#J2d1KliwV6EQ(,)F]tr-]]WI)Fw2v6]b?5/$2tM(<?n9Gs2Z]RPe7/1HSPMuA[d_u*U*X$q>4)fjDJX($0_'#GYjR7mWPfLMUQuu3+$c$\"\n    \"B%WuLDD_kLn^p:/KC9a#%:As$/xOQ'SK]@#qe-m8?,X^,8@[s$RZ.HbH4/i1U3^cVd=5g$ax7Z$V9M:O-)1#G2KIig7H=[7#?VgU+M%&>Y#:fulTKk02N$5l,_SW7fMCk)='*%$)i^14\"\n    \"O(.;:p%ed;v3WMA6rX&#I3T9VCt:/q-PUV$]Z3-vaY###n0UN(dW<?#th%T%6Jqo.N(*/UQJK>$jgp2umupUu]u'fu0wjpu_h&]t<$K>>PDNq#N:G)i9P/U#RkLxh'G:'Mu6%##%&>uu\"\n    \"UV2w$&5>##3umo%BIVZ#:?:1p$[^G)pf>F%%bfF`S%UVQ'<329JlnfLvt2vuLd]*%7^t[65ji4#1Z)<#,](?#W<F&#k:R_#d4r?#3v+G4R(i*%O^pf1>N9W-`RAtfbAE.3;#K+*P1[s$\"\n    \"$-p8.[,wD*i</W-'>s9)+m+G4ucF/2hsMT/B-Tv-oYc'&oBmD4UK0jMah_F*8alk0Kp%J3YjQD*e%JZ$v9k63)o7X1(*@k=<U%],T(n=.(L]s$W?DT//_v)4JO*R%>c;eHbn+D#&<8.M\"\n    \"q<oY-^Db0Ph:dER;B&F@u6+h)E+TC4C]DD3X:HxL=N3^-h`G*Rj1$CAw?q_4rfG*R0U^:/(Oo8%/W(kbd:j636gfF4B7E:.qtu)4LK%I6xg'u$Nok/M;QrhL^>Hv$V1N,%Q-K2'5$uP&\"\n    \":1DITkXR<$r_U%6Di1v#fkYC+ERXX.ah`V$]pXu-UslN'`Ak2C4GFT%Y81<H';$_/g6[E3705P0CrqV$&-C_eNkLlDZw_d@+s?8%]52K(S4Ji1>;cf*Qt5u`>][[>[#>A#>Y9m;wRYQ'\"\n    \":bX.`8m38&Y&R#%F053'ZfbI)54Qi(:1MZ#t(L*+Z(TlUT*m>#TKf[#S2_m&R3=T%cVbW%vpBQ&wK4=$QdCK((F3q.kM-v$Ab>?5Bndk(*S8t%qY'F.lg^q%pALQ&0((X67]Cv#iXw-)\"\n    \"ZQng)@.Mv#DNR4(K%D%,=EPv-N8$<.8Ui&/W,>>-J,RH)^oBu&?_e5/VX8&exRUJ(p0fA,7I&W$FkV[,;P-f*U(;v#)]+@50@4x#7ZoA,nsFZGog2-,@6JM)5#j+k,*c,IEZJ]IS/nk'\"\n    \"ZH8J*EKok9)F%,*-n8M)qwbR0O(bB#/bMAd[o[Iq`7amJg8be)j'Z1<r[c=$w2vm:<Z/M)n6AW$-dqF,GUm(+$,R;%/@d$,V*mRZ7&^b*l`R.,VN#n&2T&_#EHhH2[NK6&HN(k'IXns$\"\n    \"iHXx#edOT%a'450.+Hc*Sk(G=Qgqg(c6MkB<V8e,+U3Z#a?FG2>=56'F%;v#QPE**?KIg)u_G29HpoM)Qw?a+Pdf&,nHbP&/lZ#-a)MK(XIVS%Zn_Frl9nSRqV<>,lQ%##GO=F3ja/r.\"\n    \"[h)Q/@)D^#xV0<7wU7C#A93E40uZ5/kCh8.WiWI)oHs?#jCF.)Ir#c*3oAT%38oP/VF;8.eY8f3$9$$$@.x88P9wS.'wA5&,+_[sj89du$PE28xoN(TX:s=cg8D;$1;*T%EeGN>t_)5(\"\n    \"q+T.FDdnr[6Wqr80IU['`I-%)[OH;N67l31Z0[guKlr]r8d4#WtMqjuTWU;k5Nc)nx9BE#=0&pnq/.x#d2@j']]h-1+J8?1QtnrA?db(?b.vx>:;*o&=@J^@*Duu#:k%>GhGD/Lw#r.C\"\n    \"6oNfL)g]$M5xPA#`69u$Uo=Z,X,U:%k?j?#CCc8/Znnq.;7Ms-I^4L#fKJ5/[P[]4D+%]6A<uD#&`/Z$8okM(dMo?$ivgD3%8aF3VI3u7/?f.*27p:/w-J8%k`$D,<(*A-4/$w-[l>nE\"\n    \"pa_W/*7YK/a_QP/k%AA4cV8f3FPH=7S4A8@`F_H3Br@*6(#7s$ps]=-,Y];6e&v'=LHZ9)DI-t0aYiH%wDd7&St%T0E_lnAjUt<%,c$s$V,S@fCITnT*gm4&YFtILd+B>,tmvbbdqPx.\"\n    \":w3=3^K3sMK+8a^vul6%rJ%d3:(/n&V2bo(OX%a?E@W4)odZo/p8)79I.tZuXorE#6Ls;$Y[&e?36(i-H9j#9-1e_/nwvP/<6JL#=;ZU.>%)j9.=?&>Un%j0'os.$b&[D4Tk<nLx2$C%\"\n    \"Il5a40IK$80WI%Xih;Z#I0fj_3T5?ODVLIZdtw5Db1AA#%)jY#T&Ts%bn8s$_<hq9<x%P)'*@W.KrOV.Q0lR'B'Y`#b>:Ic%5YY#gJ=>#1Pu>#oWEM0Zg>A4#;+i(FAYV$wE>V/inrS%\"\n    \"lp:T/?2J_4CmQv$a&SF4L+)s-c]fkDk5Kfh7BaIh=p`Bl;gVBlOb@0rItmUm3cY3;oW)>8o`4CA3?>>#*(.eua0Ii0$cv7/>EuX1k5@e/<0JI#js/fDD=6QM&0K;-9=JV%ts70#U>$(#\"\n    \"gbtM(ruSF*ipPJ(]nr?#a',V/C&RJ(&uJL(#9KmAsw(*4xr%&4V+%s$uuF>#KkoN'3;=+Fa=Cw,jA;G#j[F?#**dbul0Hp$I<C;$Yxo]&r&v=5*eUHM.Pnw'#(H]O$^kc;fP:U%<<-F<\"\n    \":flY#ndnY#AYlR($p/]tXIVS%dFG.qgpGg(r?IP/:E-)*5f68%6?B7/MsLT/=Fn8%Ak#;/tD4J*WiWI)?QNl(.Pws.2?0I;h$<[X<6v#keGS#,k[_ZCEOk)g=V88*A?[./FrZ<jOr$O=\"\n    \"OOriuFi$ouB,w35#t=u'=t&U%mlJP'EZkfQ'2l._hWd7(2>@M'NKq@t6rQ'=+Sl##SWAe$_+#>#4kWN0#([0#OUu>#jhtgLqr;W-0Wic)Kw75/QJ,G4OM>c4KJjD#iB1&4UL7s$ex;9/\"\n    \"QXkD#w_NT/-W8f3YJ1I$-moF4Rjxc3,]Q)4mVcL#XnL+*BU:+*;rql/xL'f)jJ@d)?7sY$did8/e`$w-RJ-(8xFl/MK+#V/[O#gLO]-lL?r.>-squ-MCB0oLgVkD##%NwBFsH#-%mR>/\"\n    \"YpB:%rHUhLkRv-.LLTfLeiW^-t//L,M^WbNr2]jLkbUd-%0Q$KKLTfLQWOjLOTx'.9R7lL[]+c4$a3B#>3lX$GRhV]>*np*R:(5]w7li^.S:v#-PC;$#Q('-lgC&$XuRfLJ@h]t`7n0#\"\n    \"LGY>#):6_#6k(I3I(;v#VrRfLV'*Z#X[)Q/m@R<$ikB)NjLQ>#C2Uk+toRfL&?-9/DveO(j:ofLm(^fLY-Sp.hoLZ#;%`v#+MuY#D)]fLRkiV$H`x8/&=g2'((h>$;79Y%Q>cY#6(@s$\"\n    \"NYak'SG2[$=Ln`$+Ab,4CS(ciu)wqmBxEQ9vXD/:U)+X&uIU9&Y/*A+Ant0($b*a%5s0s-_l6?,LgcN':[.EjnsJI*IqWP&:4rZ#K99u$VBXX$@kj9%q4Fs6Fgrf<+Nfi)FtS2-xVK0)\"\n    \";LwW$I.ad%r0kX$=_Np%:+2Z#_8Mo&^5%H)[UWu$_uXZ,bMvr%O3SA,OUcfCdk->6/a(u$#=T*@Z.`?#U>Na*@o*7B3hJu%>bZl1xC/40=[Et$3;5&$O)MO'FF.[#EU_hCp;)t%-xtR0\"\n    \"e3.I)C:8bIgfhV$n7j4'D`g58W)nA4><:99t$Tb@3>=GM9QRXlJ#(V:n,GuuRafE%<j]=#V%(,).IPs%lGA^+sfBi#_7pr65APh#@P,G4_?+C/c=@8%A7[s$wqSfL_5Hj'=p:e2S;Qv$\"\n    \"CT(T/Je75/w-g:/$21=oDZb;.u>Zv$m7ME4+xkj1(lR_#]>Qc4,EjkW6rL;$?_RXD54*5&TEop.a:p,3,+CB#kISX#XHNh#@VeeYHBv/:-mwD*nH,n&_pQ-3F[`n'KH,3'1AY>#@W*)$\"\n    \"SDs&+6SWs%wbj;$.JcY#b]Os:U90m&;p5<+I@dUA^Ct<%oE&30.9,8/m&>u#n'Ab.sm<Z#Wc7p%wPR@#&8i(*g@2]u'd?T,_^LoeYn*A#3fuN#2i-s$K=$c>f_@/;c^Q/2M0T%/-dwrS\"\n    \"thv(+dj7_8D+h`$<$#N'h<iB%$`kA#;rjX%TDr:'*AcY#2?1:Te;Dt.W3d:2)G/2;pX6##wi4:vI_4q$fYI%#A,>>#,W*i(_-f<$1QvJ(@ooA$dOvP/Dc=`sPIaUeu6e-PvL?BD`1*RM\"\n    \"7$uKNACsT#c=-LcUTBPJ.]_4ah`J>CY/,I?ZG$>QFga*c;x_L[2xR.:&sGje<EH9#/,Y:v$.x-%(AP##bi%G6a?O&#_;+I#U/CJ#+(9M#w%(,)B#>c4V3__4aF,l$-(+D#JSfx$HO%s$\"\n    \"G?L]$HH3-*aSID*Jdus.W0pi'nQhhL1%0d<l*VT/<]n]4h@4gL)Hg.*UUlo7mIm92ke%s$xC:U)<BY=$aljj1T?q_4oJpkLDUp:/#7;E4XnL+*:<85/XHT7/de>9/*kRP/p*UfLYe@`,\"\n    \"118C#s`$w-(#;9/hMg.*'6$9/u&8f3*%@lL[&FV0R=n8%Lp:9/-<3jLrkT7/:8eERH^NjL7^J_1wO>c4cb2Q/C7r?#PZ3[9:*(kbjKBu$slTK-4vGpL(ht/MCi?lL8fn5/J9EtCmf^I*\"\n    \"3c#=(f?[j1V<#;/pC:68buCT/ZD]C4(W#)/&_*G4BEc'&;D,c4Ofd,*eL4gLr.QA#`gZ)*i73D#ij,V/lvB:%NpuA#/tHT/uB$>%F`*v1ndqA$0d]Y,V4ur-?3rhLq5dd/-fqV$+XC;&\"\n    \"3l?8%Bb82'kC3*35`In&86B01(bMIh^s>j',jMs%`v9Y$juG8%_&2S&SB=:(G4)?#59]],,BD7DSrH>#2x?8%MtDtS$GF(7Y8TC+/OJ30pHXZ#EjRj2q+wb<a-eY#2l$t&Gme(s1j%*+\"\n    \"8%rV$g(Xi(k5P5&;n/q%>*G/(@K_G)6@ns$6x6W$B@Vv#;iuY#?cc>#0](?#@*^2'(H5<.M@vY#*#IW%*1s]+%.Cs$5Vl>#Tp9u$SSn1(MRGH3F^eD*@`.s$D[1]5fjK>$+/MB#'dL*6\"\n    \"F4bP&iE>p%`&ZJ(87Ow$34nS%H0?gKCp/.*3D=&>LKX>-2m,<.;g$I2v=@C#-LMn8@rLZ#FReW$_a4A#rnl$,lYiO'E_*X$Q6#N'gt'V&%Qv[19]_V$+s-m0K.ugL].G&+1jCx7Uakx#\"\n    \"/,@:B'_u>#CHlj'IT^Q&$ktl&YKcf%/W8s$5(Is$7uIV%Wd=]#9`U;$HdcR&1M.GV).;@,5,721R=Od)@%Y+b3`_V$FXRs$ts`uP1fhV$[cYXl$b=C?(8[O(Fr+`4$k&V.K7Z=-,QE**\"\n    \"SP4E$GIE5&^U.<$i0lI<3.9W$cFX@RZ+=+37C[>#faS-DjFa.?sbap%Vvdl1Ip.H#nkt>$fAIL(&5[E&xjT6&5&6s.;Rd%/5mPo/<U6c*<[R&,cfC;$_uI1(Mr0s-ap$h(445e)9REp%\"\n    \"V+0/)oci^4UhXmL.(0#(Lexi'C0ZZ]gIEp%0JP>#TKp2'77[S%i)67&RhRw#1uq;$<FIW$=o?8%6cL;$IUOf2Iw%k9;nuf(CHM8&Z(@N97)riufNa/.4Yc>#I^Y3'#`JT&pDmr%un#O(\"\n    \"4Xgl'GYxD$C<5N'4(5`4sd]/1ruTS.viXv,^rF5;.VVOBkSjOUFbnS%e>l=$PDi/:1x$<$cm9H2;C<p%qQ[T.P2gf#C#ma,.R2s#0oUZ#,MuY#Z=b6'ST1,)1eFQ0##3O'C1[8%I)NA+\"\n    \"K+Is$a@@W$H=.<$)Laf1&&>uuYdUV$^)V$#$1oH>sCJWTXnFb3l@n8%_cWI)tfeD*ZHuD#C;XQ')(4@$gG^.*Mgs9)n1/>8VbNT/')ZA#KjE.3w(]L(Yx`=.1i:8.f%gGMt.,G4^_R`a\"\n    \"fS'JI=%Me$tX@>>L^Cd)PvuA#5UlD4h?LbI<3we)d>=mB78$=7p[2Z#0I>PM?[lQ&U9Uk1Q,rUqg5[',fkYP;=W+8;0h`4;LJX[$BVKC-*h+^%/>SD3NYG=7?o<-.&iP_ATjv;%PKtp%\"\n    \"B7GN'9$P/(TTe,*PUVv#<>@+6MU(12GRv22j+*`#+c%12)#:=@rTl`*ne0BTx^-on&nwi304n0#&hj-$vCv##xqni'[1pu,^l1A==;4GDHK?gtW>6#>0X?T.r^[g)/>g+4hHE:.IKj[,\"\n    \"o1pb4N<Tv-<JaD#u9@+4?Jn;%[er=-9:eM0r>^.*I5^+4ZL#gL]bRq.,'A.*Som92s-g:/On,D-wS`]$Rpt`%Iaus8bt=)M,*)c#`qke3S=4%$$0,V1W`mZ1dhoM'(sbv62BL:%7PY>#\"\n    \"mT2AXW'caa<_&f1O[#MEk,KC.Z6^B##n0Z-'WL^#7tYj>9OPN18wd/9:xKhLd1RQ24&qq8vtGg3OufP'`:=BV8cx-F>u;*4t,kEEGbjp%Pt*=$P3:T.?1)VQuCY`-,Ds;K#VAVF6MtbF\"\n    \"Hg4C5H/u$6#n1Z-)8[s.2(V$#BId(%BV^2#_UG+#/b.-#G=G?%Kt6VZQTp=c/H0YlfA+##qqSfLK>6N'X7^F*OINs-_)VV?3#ra4Jc7C#OM>c4,fZj9gwc,*#/`]=8']n3$AF,MkQrhL\"\n    \"`(NT/6s6@'J_lS/bYu`4E5=h>,.ikLIfN^-)NPa?U3Js$2+m<-2WgoL'lx70+g^I*Y.i?#v+6U;V=8C#BoF#$aEb9DrOd;-Zmq9MjA,gLSW7Y/@f)T/Nwc12+)e3FIvZ]4-l)mL^c_9M\"\n    \"@btD#<s9,5,dGP3ZEn(]>%<d)Qf=Z,Of$?eqttX$a#,vGZhop0UejT%CMdjZKqqY$`%dT8$.(T)Pm:O'XciG9_jcA#6l:ZuG_og:Vfq,$1A`11+ueUmP1ZB?5U%=-4OQG*uVLo8m*>31\"\n    \"`L$P;lDqZ-m0l/2O:O_&/pL_#E*^K:l;jo&cLaC=dXD-*Co9_5EpsI3d[^80ah.<$I@;0<KC#jBU6+02_3[K)mW.'4]YH?#4rC]7ivP;$Y@YC+1Z6/EiUwH3F>>K3CMo'+YR#B8P:6V@\"\n    \"h>/r8X6RdIVuS,3>QV,)oO:Z@fn4^@'Afr2<:E=S>omW_GVQ;RC=dp8^ktX$N@>/C:Xf2hF0w_#Ha#9<<i,r&JXw>QDEkg;V`7<$UC5jBJSXvm8`^u$Sxfb*E,,@&<3weMQVW786l84;\"\n    \"@Cpg2/8Jk1@a;0(F*[J<`3Ks$5*Dt83WvS9h*ST%h`p/9Urnw>.#JC:I6`g(3_x(<O3=v#4Hsa*.h=N(S68->>2M;?=1n&Irxrx&F5c72JBRp0AxLl,RR2B+]#Lu$x1)G*Lb`e7TJpl8\"\n    \"&B)Y0UN=E?.*P@7pSOl]%]B12w[/[#,g08DE'N]Fidcp.b?65&NV%JLUM)mJMDW]+9lCYGQ]BuuNM&#,&NGG2CD4;-bA.gYi/?/((6pV.W-Qs.h:C58_Yc8/j85L#Ei<<%#,B;-Kfcs-\"\n    \"t@SfLv,k?#qwkj1I=x]4nNJw#(cK+*c<jv6aAL>$`L<H*ZHuD#t;Z50`26N'pT%],l/)L5Aq5V/w5Qv$L@kj1TDm;%k[K+*C;q9;xG<T/:jE.3ll=w$n,U:%@f)T/L69oL<Ej.3]v$i$\"\n    \"w&hBJhgw?92^E.3(hR'A[48C#iktD#e&8f3<#j;.OgV$B$i)Q/9GlBAfl(E4O29f3%gIn<4R7lLBsXI)@-D.3a6Tw9ji_U8iJkKl[QiT/@J,G4BR(f))thT0tf+/C$%(#,TOam*/B@6&\"\n    \"x`Xeu9DcJ]aedC#uO4:]gQ8rIg*>$/a<c1H%][9%M+2v#rSM#5GMTY&?Up(4Q&Q7&]1'J)W^5^=QdeA49'vZDTD`/HT9Hr%/]_V$;%`rA?/8s81kn:&O=Tp&Wo96(MV9F-@Vu;$7aUJ1\"\n    \"@x:Z#d)(n)CwixF)wRx,YJdY#:l(Z#jD_7/P)M4'@o%U/spxN0GMO6'cqmT.UilY#E8/W9_cXV-+6YZ0uSG>#-Uv68>c(Z#TPTI*d%)?#Vq7/1>swd)%<<*4X*F9%T006&HK#R&JU@W$\"\n    \".YCv#It*t$S2I-)<33P]9x.r%ff+c4]qvYuC]o>,%vdn&9.[S%PcYYui'mY#Z'bp%QLEQ&Qx(?#.fi&J)*HruHoh1f:q7T#$,<D#(Ln6]27%PSWjkG]l&s(EekpH#nbL8bZ,0^0JL7<$\"\n    \"aa%3'q,E&+W/$$$od#e<L1/-<uq9Y?b0SW$ciV(^f21]8k/FVAkkjM)@K_,),%sH>7q#n&)#fZKJKV^#`uuVfKoP:%vVh,DG_L6&^]C<H)BQ>#>u5$,xoVO'*AP>#D3YC-1$DA$p`A9A\"\n    \"*L.K:<2`;$X^O9%I,=BOc_#j'C*no'LYG>#A953'04`f:=VwS%PKP3'TsBY$<(7s$ru@L(_4)v#rN4X$oC#Z,Q'Ot$SmuN'x#0r.D^B56,vK1(<1ru0FQas-H]rv#MnWp%03_oSgj^q%\"\n    \"T<fs$m5`K(X;n)*YDo3%Aa)?RQZg5#xVYX(N9Tv-G$5N'@RIw#hj'u$:UpA$O4n8%:$wv$P4[s$5?(C&xd5N']YRD*]D_e;3ir-*[+]]4ji[:/>b#V//Xah#Ij:9/@X^:/N)b.36:,gL\"\n    \"_P,J*dchU81>Ok4)NL_&]-_fLUP7C#-`H)4]x(t-olOjLv975/qiO[K/C7lL2Vob--nv3+N;`^#j^ZC#V?ocH66Zru[2GDM)U>b#Mj+T8R1hU@vEa`+(BbB,]Ysa*Kspn/`qN5&^rvC#\"\n    \"'e-K)%EM3;J9dR&JZ$d))sq11<AdP&9GY>#+eNx@`Kx8%&./<$niZ)Ea-]s$dWgm&ZlCZ#-chV$hG$7&m]@-)<Ztu-Ik4w$xT^Q&[OL[,O$x<$c+FI);iL;$_vBu$d0k5&Kt=/(cCY?,\"\n    \"bTPr/duHC@<wWe;DXF;/JtJm&v@kE*bAR-)YtsZ#@?lj'4^RjOx$FA+&ag9JC+;v#YV*I)[d$H)V5>%MM%>N);7HK)EkjT%370P'Gh?0)fYIP'uED)+(t*B,la9:%D*Z]4c<Y01r9>?.\"\n    \"i6>k'>q7K)fr<.)'?^V.(Et^,$7@`%;d(Z#3oLv#FNL,)*c^J)a`Qv$d_YE*,=%T.FjZ)*mWIa+iTb5&>^Cu$,[Ix,'r2Q/a0Tm&sPdA4TGlY#JbJi'hvJs$xFX.)sC0J)=r_;$$dRG=\"\n    \"xBJN0IA5##l(UAn(-VpJ']wCW1O)##Y>2g(YcX;-l,Ih(G:Pm';CI8%&@vr-lj-H)humPhbrV<%pa5N'[/l]#tfeD*O=@8%Y&dV%D`E+3+2pb4/N/W&Yrjj1[KA8%B;Nv5V.@x6N;Nv%\"\n    \"Z/QA#c.8C#$mi`3Jj:9/#0Tv-VsR$$EV?x6pIsO'1W[iL.v+s6Ak1B#]K5,22-_3'@Ds4fP?ZlfBH4O)pS-;%N'd$%qkX2(hk[8%/]U;$64nS%hf$tHL(/$$SaOA#LwI<$5CZ$,eWK6&\"\n    \"/SuY#J`@tBqe=gL`==Q'RTG3'NqI<$1l'F*lG4C5]pL%.Mc$s$/`hV$>%)Z#-AY>#<0CT.7.@s$oK=T%:hAm&M^U7/j-VD+]$jjVJ0lJ(<%I8%H=h+$#WW32JF`;$s,'v-CWHE3UB,mJ\"\n    \"ReG`'EFWB#fTYn&+AP>#FfGd$7uh;$0JP>#_fY/*O)]k(SB`f)'U<U.v;j&+0=dC+-0tU.'l^-)Mu@)=YqnW$Rp:0(*`K'+O0fu-AkL-MDH5gLf>Lh0qW+T%qrrS&[.]fL[]bA#/]Cv#\"\n    \"Nm*Z6lK0*<`oS1(Q&.-)q[)[#LQ#n&RWYj'%hRx$.i#,*uM6;%m]$V%tg+9%HQM,#wq>v$a6W;nGsD&+;]vP3WI$##pQXt$H<4U.@l>a*^$&<-b'd97PC@A=^t^7[=6HlfYO.NRd0%FU\"\n    \"8o'O#00G#7+d/d)re&<7T#sA$a2L<.eRpI=6xB<Rd$epj9;2r#Z8Ok+aa>`&KPUV$I>x/&]`3>5X&=J:&a$7/RBo8%mSvJ;4WCa4U<RF4V,,H3;X^:/ANj<%b2B.*ubLs-w4Hf*'BoDN\"\n    \"pZH>#'KA@S$lSu#4tv_#Gigl,5tm`>UfAD6l)G]Y7qa['C9p4MM^C1pTSNlWJtn48hXSR9>xBHM%+B/LsfRGEqYa^u3=X04Z>+GJ*c/qLq3#X7ZXr&88@f;HgdZrLsqOrL[P,s-Rr[fL\"\n    \"L:7v$a0-;#gFKsLCHY/2cu+G4[5ZA#Rc@A4pFxU/Rt)?#d(4I)lO<v6G4[=1OU=j1-Wgf1iHUw0<Ng@#AB=_/O;Qt1-0ot-h?7f3sJ))36WLD3J29f3R]jj1m('J3APkI)]AqB#QX[6/\"\n    \"<iXI)1IqhLOU6S'Ji08.Vrc&,><l5&06VZ#Zpc>ufjY>ujFIsZr3LT&;YDQ&ia4`+IIa1-7^u]#$MKb,-Z5C&sueCN$I:-PBXbT%^r6T.=YN'@>f4*Ql=B@T(Ke8%8Ah<$9?^jWFq[TU\"\n    \"0WAOl#[XU%Xq@s$:Zl>#Q>%[#iql>#EKPYupp(?uhC>/C>g0C,b4IQ&bt@f1Ul+g(;5bt6KO(l.:UjxF*k%VQ'Y4Au3CxT%Ac&^':DQ3:Z?CQ&[:`C,i^j@,W/v^=2^7+HGBPj'`dL/+\"\n    \"uieH)^xUeGXUgA469s[$SBP##;PUV$?@;?#:.G)4D%TfLlkx=%bw@8%$ImCEZx$/USjMigPn`W#Zk:xX-Pqfu^xnK#O8vN#vYw8u($K@<t&3@<&[V(N]4n0#Q;###@pO5S/-;N0d&U'#\"\n    \"g0;,#<qG3#M1@8#)QA.*kpB:%ok2Q/?]d8/026J*d=+D#)XnhMZ]XjL]-vhLP8^I*s))J<FM7U/Ys`a4qhpr6R%^F*9L;=-vw(.Mn>E.3m10j(.@C)N5-HD-[UYHMGqLa3g<7f3j?]s$\"\n    \"K?0u$(cK+*QG,c4XTcoIxtsY-^`Pn*QlvG*GKNe-6q5V/w4NT/NaNjL5+F:%30Dh5]x?n?M)pxX+O#j-uLdH$=oVL,bqmk,ShI:.+C`2PipTSK`/RG#B8k+NrQ[MKmr$vZZ8Ml#Eke@=\"\n    \"1.j.$?jxJLE=DmOT=ad?HE&;Qf:*NAwjT$-($:2'gL/C#so<m1lT[Dm)?t#-M=w8%gtR<$ZeHt-t.oP'^cj**EJVx-oWbt$jrrS&oa]w#I#@-)SuCZ#7l89&`o'#$3SlY#O096&4%@s$\"\n    \"rkA/Lav@/(%a2-FKdjd?p#;jX*YK%4SdSq)+=_B+vW1'&t411(.S6s6qxeFJ%K^VK&ILx8/)o[#*fO%4o.B<(m$A'&1ALN+J#Me2/,,Yud/#MbT[[=-N]wV%jJ,+%%C2<-b0.g)P^?7G\"\n    \"->tV$MnmG*8PoL(M?'Y$S?BU%j6@9.u4f-)9%rP/j34x#SdGN'`Mq58tN@x,HHF#-8S%;mh45)+a:_s-kQlf(Nj=;$hJ=uu7ao>#NdWf:>Jk(E:E-)*ACI8%l&PA#?1[s$Z_d5/K@gfL\"\n    \"<9+Q/&SQP/1?Ea4:TID*#7^fLL?uD#iq_F*)0dA4CmLT/96Tv-(SJfLV.[x6YP6C#+IA8%hUK+*FO0R3vdit6<w2FP(g^$-SsEj9uZMgCF'iS,AwSQ&jd?1gKWNh).m_Q^+awd+Rw5I&\"\n    \"0)jc)d*_:%Jv?o#)#4H)V>C3&ofvn&;78Y#<jh7@5JYYu`^jp%MLqJ#;UwW$KZOJL:BOs$e/obiN:rK(HKpU%ag'q%r=rG%e7l&YTK..eDP;r%hi-Z$Lc[t%D7.W$a%w2'orLB##QMX.\"\n    \"#%'a#TA#5S>+P&+:ONT%vH)bNJ`4?,V)_B#VJ%P'IWbq#m9`k%``DO''i-W$QUMM0C>t(s9iC;$KOPC)JKWl]4o:?#k)7W$RiVN'OQX]#FTG(#7&>uuMtvc$Xa($#IR@%#bEX&#$9q'#\"\n    \"<,3)#TuJ*#mhc+#3tI-#V;L/#-fa1#s->>#7U_,35Z5<.3H)^4=xCT.W76J*TQ&q.u3Cx$_9#44Sxw34%`r'8BAv,*r[2Q/bT#L1lT&],q2Gg1$$4Q/bSf<Ckf)T/Q?1d2WS[]4:>`:%\"\n    \"A+e'&n.<9/xH:a#x>VG)+[)I-;9bs$b9I)5x'b%$5)gf3>(g2B<b2Gu&x8?&#/_(sK>)F,$Qnc9xH:]7x`kS8I&QEtt@'^-?mtl]NKTj0C&3P$9#M>$G*=]#fC;(ten`G)s;92^#)*t.\"\n    \"/-su/4#>v6];?=8+s%ft)Ki<-&8@60EKuc2>Lqw>OSv(%Rl=?,NDW&+hq;@#DsW?%=X)n'/*t@=)Z:50=$6X?<Ph[#cWn(5-B,X#4kW>DIO'TR*Lv:gVNAa%[HS8%:&_n/U#Q01L;-o/\"\n    \"$iMU8_&dS9Ef2u7VX)C?P'T?A(>ZB?pJ?$Amt'[BLkT>A&jqpC5J1/C3XMcuoYb8(h*?x'*;Wi:vlkE,ui&E-Tn[8%<B8m*$*&U/9QC^#/`(?#WcCZ#b@^T&0(ji0'7>q@f[RS/uUH@)\"\n    \"A`U^J];N@WeKHnkoel8.cM9##-T-T%>glf$cH4.#`;L/#EK;4#Gj@+4uY2)3b6FA#[Bs?#irne2ZsF:.ZGD=.<nTfLQC_kL/tHg)H5at(@U6L,;s5g)M:.6/`WSw#/Mo+M2E`hLs?i8.\"\n    \"X*4r.a=7[#p89X:DF,gLvdj?#Uxh;$,xF)4PDRv$%A8U)YN5<.3HvA4XI]C#?[tD#53kU.+#Vv-=@[s$nN.u6<^ud2B.i?#K'_)=&0,0e]GhF#]mj1#AF,F%8uOR*N>G>#VuRfLJvX?-\"\n    \"D<`IMe3[>#-J(v#(f$PSR8cN#gFXLUX%>M^Ihd&4g0NPWY7RC#%5oG#(tFd3hiIKN`=(13W,8n1wK8xk2<TLS@=Dg24s@O;DD%q`OR[iT4?V3Oh0gMCdF^4OY3UPNbuu-M>?E`#&'Fqe\"\n    \"eeLwFxAqeuN/'5Sr*Y'TNN@@uGko@#0FH3<9<qq%Z9X]#bo37:<k,R0(O/@#^u/eX/%=W%VhT:#Jww%#9DW)#O<:pL0)`>$7x:;$D#Le$0hTD3@^A.*4_a/1#5NT/0XNv#HmE.3U?'W$\"\n    \"OFtY-LHW[$8-U:%^h)Q/Mw60);@sAP):#'$25Uf#jYQ_u0Z2WuJcMsu'o)`#T>xs:3d*s%,hW2)Kq6gFdbrQLeB-l35rWt.f#)K(GXM+$..@*./6Kf3bRbX(c41>9Vuo-)PFru&wmMl(\"\n    \"Z4[79Wxo-)Sb4U%'6CkuovbmuS?]O#/7#F#squXP[PXS.:[DW#CXs;.sQSOur';n&&L$L2(eED5..vW-[FA@'m(WM'cnEr(85G>#ju6`&P####$&>uuvdUV$$GqhL<FxC#QY(?#R(]&4\"\n    \"6=_hLo/g@#h+0f)UEdtL(9k(Pj4VOu:W_l#.@CR#b1^]t1I7#58-p4/olhPuE8^G;X:Tq#@;+K_&LYqV7b+dt++0&=aDkV'+@c9D/3a9Du8#<-6/(](O[nA,uwWD#>5oL(ilWI)X8%H)\"\n    \"SdGj':=@8%V)uVH,>`.3RV>c4rquh2Ch_F*U4kD#U`wv$wv9GdZ)E.3OVq/)KPsD#4RNk+=jcrH]rUpj/?51pLvPm8[a=T%3U=]#(>cY#7VG>#3r6s$2SSHFWs9B#h`:B#3MlY#Ui98.\"\n    \"Yb/6&AvgG43?Y?GE3[o&kCw]%P`Ei(sCIW$@J9C-l'+v/0MYb%-IvXP''MX/,JuY#Ip_k'-G'C#INBY$^,tD5_QHD*][NP(WFGJ&CE%'5X?#LNSa1[#CK0K#jp#g(uIwA-qx8;-3f%V%\"\n    \"6$q%4&e#5AMT>4Dbt)Z#jvBu$^4^F*vb^>$l%o*%@Gg+48+R1Mk1,G4ef6<.&W6C#K5/.M3Q_:%BNk;-<0=r./0w)4M%qNOV#p.*+x4gL6*4Q/H5f)*;vZ]4V%c-?_J-W.CP,G4b<o7(\"\n    \"lxtFXZrqO#*oY(+$phi:RJfvVl8kf2`_M^Ok5;0(M%>I)9BM(v]o-(;T^lN'f:Hs.o-<ZuNMXM(m0V7sQ)8(+wSqr(6+t6J:@hq#UW([.cDrV$ga_ju-ren&a+A/L@='U%,DOku-(o4'\"\n    \"*gJ9ABV7GVJCqw#KaH:&/(+rjN?F@,jlZt$iY5R<mt)F*>:vB(OIx60fe.w#x5]VQ(`<fLx@058hnXD&3'I8[Fu5a$t.*8&m<Ws%+U@,X0CVO':JuuuV8G+%QOU/#X[P+#=<x-#bSq/#\"\n    \"mv[I*QWTM'Rl4Z,=RIw#0CqB#Lun$$]'U&$RR^fL/']P/ng<c4eum;%@4[s$Wx[]4:c:5/Zf@C#cDQ/;*5=V/Xc7C#_SID*COu)4D_K)3q_QP/^0?,M2l+Q#5)E`#GNA`#8&aL1_>4RD\"\n    \"dA598Ti9t6V,bN(.VSL(PC.D%xt?x6jCYZ,p]<e)(eaL(9#gO(N8t.=5/R_#>]&;/T_0A.Bq1TJB/T)Ab(D<$6Fs]uC*?>@<7jw,P?*OqOXP&5a46%&4Eo71$DBZ/h?LJLu0sV$2r]l'\"\n    \"2&2m3L/[b=4;%[-:hs6/UPvk0NMI60tIB'+8C^t%Lu<w$t0@t-9xFM(clBi)f^m8/53@iL/^Ed=P45'$XR2G>B8@eOTc&1Mt[Z4(`aU@O:AnR&L3Ft$O,77T&n))+t6@t-hMIf2-6bv6\"\n    \"odwA,I6>/(_7$##V[V&&F]>M9rd%##:H/i)DPP8.M)]F4>.e;-FORm/i>[L(^FxU/j.LM96;d;%KEJU.8_Y)49]rS%,Eo'RhR.d#w2/'5o#kH*tJ]B5_gJa+IoZj#K&%-)3IL/)QL%[#\"\n    \"kLL>#XSnh(vMRL([TgQ&hYTsL^'M_$:Pb?.KEb]u4)c-*@SWb34#ES&Q>(i:@BpM#N4-g)`KB6&g7BF*k?jZuH1v[-s==.)E4i;$o[#G*gsHo#a*0Y$Qt^=#onY&m['3$#8hJ]=L8DX.\"\n    \"j,%1(6tC.34+gm0?rWEe1Huv*VIgK1Ocx=CmSJBeSeCBf[.]Oi7-.AOHuoR<%tL*M8%cW%xiou,&N>G2=/Rk037K,3>U^:/jBuD#P'm<.P]B.*(_Aj0IZD.3-4UB#<Ch(EcQb-u;?ED#\"\n    \"2?9oKI<2c5-4Q9h+rpw@B68taOUQl$kF]>-uU;b4,PvqmhR:1EM[UgC*+F+?$tl89<IC6:?1+T%ZcUV$krn%#D7p*#hrH0#r$B]$kbK+*jj5/(=Fn8%#?P8/qwkj1o(8_40(RKumND.3\"\n    \"&,]]4VxSq)P>I&49TQ)<NpIn3rf%&4h6rI39EsI3`9ki0d:+i(HPmG*t'lO1X/Ao'Yk2Q/Q);9/Bix<CU@h2K@Cr?#,[6PfY+tH&?x:Z#?'^m&Qqa[bR,b9%/J(v#&U6l+4T(D?vXc=&\"\n    \"VChs-'rg0I)^P$,->G>#<C7[#s:Pu@S:VH#055C_GsN$6aT3d$t02w,$9q>$$)u`581n>#/o$W$>R<T%aPq'uxsuQ'[&e)*2`eZ$A21O++=^kF1oX,MZh^b%N>9&+wAaZ,[0@>urA%K:\"\n    \"<f65/Y+Rs.7q8W$OpVNp3/Hn&9U<t$-H,29o3eXC2K5B=47OK(pJ*I)s4jK(%J_;$Rmd@`?1*p%oUgb*4o=2(63@=b1bwQ/tvts1=YcY#=3b<-vFG[(6Y8a#J?gf1o-xB0c9wt-pK[+4\"\n    \")Qj($`k%`,^&PA#-iXb34htt$jx/+*CE[hCQtwgtJk.T%3'I38v9$#8AYT782F9q%,;GYu`GZ.<fri^#J@0Y?/w)7'_aYD#l.2YlIGta$+w$A-W1ZZ%4ZPN#mAlB%=#'e*'[khD7TQ>#\"\n    \"KXfi1Z#[.<1F@vn4kVO*Y%Sq/%<;R*R$rP.J.39B<NV&#J]tk%Ft%###W<4BpiUE4.u587.UqY,w?&j-wmf*%iC6lLVP2;?Pm:T/Jj:9/lD4j1=nTk$hY=8.k-5N'M-Jw#2Ru)4')'J3\"\n    \")CkM1(],fC<)2h1f%#Z,:/Qo/@05KN>L`W->^^W7ECR8%tX-r[K%OB,);2304Pc>#s(]1(vL'97*idT.Hbv?,#b,r%rI6#Jqf$@-K,(@-[OjM1Zr1F4q17Q85o6s$mn([,[hfM'ne2v#\"\n    \"Cbj5&>:w#-sR?-2[;j61=eD11(I'6&5WxY6Ft)+3o3Fp%:#>r&<4oku;W'S/1ZhM1;ECT%j]_r$Yg1$#Vrgo.[OQP/nnbu%F[VZ#N%&47A8&/CU>2O#^SRiTQb8`u9WuYuSG%E#fU-b6\"\n    \"`47fUBsZQM^uX%tY:VCaZLOgLQ:SS%n,W<#Q>?pI5w@I*^7pu,nBIP/hV)F3BBMhL#Fl(NHajvPU1BO;/6YV#s=cV#,w2XSMvXYP&0wJ;co&8M?7rp.7k'/q+IA1$bJDT.+&>uu9UeW$\"\n    \"GAO&#L1g*#3n@-#[;L/#Z->>#NqSM'xZ75//s8n$MqV[,P)n>%kodi$W=8C#MK1h$;29f3Yh7:.?]d8/#i.+4FQPA#$DXI)(#;9/1m+c46i%b%4m@d)[S<+3EI[hM(tI/3SPS)*&1v,*\"\n    \"('e)*it_F*[pLT/*H)w$-7hcN8,[CsU7io?lm;C$CvfB+@6Me3>&>B891*<MjnK60G#kVDXq<[,s?Wh3LBbZ#L`O&Lwbad4^wIWA]1.#@$[<46RCpZ7g9vv8';&$$222O1Vc^u,]PMP0\"\n    \"<:`N9Tr,k2HRd*+Un+msl?^+[$hqF*?[<p%W*BF,,?%VZ5B3l];OH)<QJ,E*bP(%&4<[[%xE)*>5l2v#,OV.=]3;au[EBOG[7HI4g`]P1IsL4Di5`_/3*exBh=>5A'XK=865RR2Q/>mB\"\n    \"T%f_,->'32&Zg],894#-E:1t6R%iA?N>D2UVmpp.mWT5:o*l'4::_b*XA###$&>uu(Mjd$0qm(#1U5l1&`wv$Y^D.3P`&E#UWTM'WUHp.;wkU%;Pd4(9jE.3hNXA#q[R2'&.]n9;K'.[\"\n    \"V6kQ1gXV?#Y^aL#0_Hu6+_>ucdsgg4D`YY/YX+v#b22[]21xg3SulY#nfQ/(#fjX.o#]fhn))[+0bP70_,Hr%d88GGgtV>#%TGS/emFL#ba.>Pj6.q8Fona?;48%#rtre.^&%W$nqI3%\"\n    \"#Y$##;EsI3o[rS%Nc?X-#Qd*3ecjj1*RPQ';U,d3=/^F*guJ+*@a'_a<E.Sm$;#ciSw/dYkXwV-=2*TCDoEZ9FcQiD`joUkDP.v#-*^g:XvjVYpeQmMN/`p/QdSM0Dd2=`=]Mf-kndXJ\"\n    \"a6e'eHJxj3,xe_uO2O0uEW8r;?Gpc$;b]*%R0R0#g]Q(#DG_/#K'Z3#n#]I*lYWI)P8lCdA0C]$i@[s$m&l]#@pXv6`^#V//$*0a%@vV-pTv)4QV>c4G&ahL]>]s$[d*j1Y7_t(h2ahL\"\n    \"OgY=$ax%C#T((+*xCXI)aR_8.bjn--v^v)4+s=JMGIk%$M-M$B(B%<.qm`a4nKc>-bt1IM1&DT/qsoX-x1f]4[/.-^UkV2k)]bY4o]DW#b<RA,[af_R6ImCBkBxT%'x4^,xEvru/>T1^\"\n    \"-`K[6BL?8.nbL<-h75xtk(/:b^].<$b0&s$Ruj4SVrw@#.a0)<ImPV%-J5(RpxXiu$5Y^/V(M?##4a1DR'V+d=`/&+#p2,)NlTx?FQoiutK_u9rqnu>Db1?#_odp#3?N=u%NTkfQ-@8.\"\n    \"VP`Q<1WxmE#O3q.r$].4/2T=^u(.602-qY.fc*`-W?T9VVM$9/;wUu?ZHg;:noxf3K[@$7qLExJ(:2;0=ith<RxJ+*ga/O2;JOaubN82'g&'3)CsnL2Y(Tk;tQVA5<u-f=Kb9lW-[$o#\"\n    \"KDtm1OFKFSJ;#^S&Tpq#/'QO#'<CM1_xuu#ri+##D(Q##&Zu(3[x'##JbXF3IeM1)Q@Su.abL+*^q[s$]Tj-$+`[j:o6iT/TXUa4(xn8%R.Xc3;kRP/T$av#[s'Y$eit1)Zf@C#Wf-]-\"\n    \"sZ/I$m&.F%.qB:%@f)T/?D,c4wo@A4_xCX:2/0m0%F4i,j]gG3uxInM%#qd45*4AFq:M[#k])&4A;/X#bWKq%,llM93fppMFl?TLNY<s%mRG/'dF*LXntV7'4P0:TPBB[#G*Z=ZoAuA#\"\n    \"TvpQ(b&JT%*mIX%uv`l(,^8B+b<8W$b&lT%-cH5/lpKD3ALi;$@caW%G[ws$,vCv#4`4gL3SSL(9jw[%(p6W%v)>X7C%RS%EEWm+scn]+<is+3,WpsuH?`J&Ktsr8wKJ,;4On]cJZiP#\"\n    \"RVU<TWh94T_+1[3kp0_J/rdtIH%tp%U&v7&l&+Z6PSVm&3M'?$5oXgL(A)f#3jwH)ROiv#Q*UgLVMcQ'MS-0)AVw(W.'We-(L5s%'/###V7+gLMWO&#f&U'#;2<)#aiID*U=)?#t(MB#\"\n    \"ak4D#VA@r%TE>V/2NX7%V2Cv-V4wP/Ne_F*-vY8/ChlA#Nd511+-NigG$<n(dusi(WP>s-Gn](Md`?C#i&MlG%x&YYVLeo/?Jr$b93dr//QspA=KGSIULS:d=vRdu75]Cut0Trd8YVIN\"\n    \"qj<l(,6o9;/;Oe6hr&YYK/]oAKkP9MrC(T7s?Ym/agM%O1Q;>5@R<=$/rVB#jn+##(8P:v3px>#&59;-=n?M9u$fu>^r<$%4['u$:5Rv$1-Tv-xg;E4x]DD3%kH)4PP,G4MG9(%gjCD3\"\n    \"6'PA#]::8.:=6g)lh)Q/CU)P(7%x[-nn=`#W*,T%TVS(#0Zc8/m[x_#+542<G59bupS9xKYjo_+(nckKvmxtuol&G?V//q/]S%_#icn:2'Cwx,=/ueh_XJB_Zef0F@vi%Ao_$s/YD250\"\n    \"Z?4pLbuMe$2`3*EYOt9<#H*dYDeBrU%-L62r9UP)PdwjL3wj_5E4V``S^2vAnlg7N3;Hf**l(2BwtL%BVJo^5^_OD#/s7L(O`>>##&5>#4`:Z#w#[Qs1EDg(P;c^,]&PA#xOi2:qiDw$\"\n    \"kUKF*4Yc##@th0,)AW&$bfVW?rgs3C0KaPD/X(43WUwHD%PY4]rsL;$g)QuJtrpiu4m)GiOsfKHl4g>.8-NA+:VXHAGfH1pHep&,3?/@%h?eoK6iMe31O19%[WCQ86&X>LGqAPJ+bs[I\"\n    \"Rx4Y]@=%_SL5r%bY1vr$DTCG)WkQX-EoEb3?\\?QJ(9TN/M:k&K1LEYYu<vP%ttc/k2MZoe$+cCNt8+J73hdl53;lQguAdL*#S-0q.5f1$#>3`'83.5F%p6=A#YxF>#@oZCuHBeM0O0x1$\"\n    \"(C@D$MbOoLm5?uu6qtM0Iqn%#j*2,#O_S5<viJx$HO1x5u'7]6XKlj1*@qX6VBAW$Oss9)6tFA#Lov[-5'c]#w;3E4dxrB#k]>_/_>:Z-/?ut$2lqL5N9*I-c&Fe-Ni2H*)JJ]$?Iv=(\"\n    \"GZ6U%>[&b(_Z4>'P^ZD*kJ)g(E8qp%9i,7&'6E9'KL7@#i)HmSR'=9%SO4h(@M)4'Rf.@#^lwd)x*L)Nm#sbriLdF#FaF20L9'6&PXRW$B[@w#$(@j'6>H5&L]iZ>Rsu3'=`qB>Gb7@#\"\n    \"NPTU[b;)4'l=:[-i9Gh5f*qh5+aWk+v2v3'@DLV%[Y>##*8###,`1?#r/))*&Zu(3v3FV?t<7SR7-CG)81[s$wkH>#VNGs8#]CE4E+ro.wsMhL>/G:.+;@<.T-h_45t6l1O@@<.gs#&4\"\n    \"U.p6*U5oSDXB]s$l#a#ned]s$Y$D.3O29f3GMrB#I[1EN'U[5/Q$F7%05B>,[M8f3d$f8.iL0+*/=4Z6/kqb*i48K1Fk[@uD;Rc<^^xOS<,Qb%ps^^#NS4U%xg;J2V>Pt2<k^`XIr.5J\"\n    \"^PlY#0+wo%6?k>7EU[s.oSVk'E@:+*VSh$--4(E-uXti(_.N3*^^^Q&+v'NCRr81<wOn:.a[4j1-(<`+>Jxh2[-X<-mtkX?B2Z8/LntuH4baOMiZBcN/,ChG*qx[ui.suLJ#x&G3w-ou\"\n    \"R/)UB]mp3SKQ#3'WL:[,6F0F#[)xN'_%3X.rB8@#K78Q0bZ8QAt>vx4>J%m0t3)YP[%0+*3%:+*OG@&<0c8m&k7v1:'q0Y$5)ab=DHGv#$3540_rTF*C@@s$$&###kC.&bscWY,*`$s$\"\n    \";J-W.`?7f3r;Ea48-U:%[YWI)RtC.3N^t87V#PJ_<1b0lsw-Mf-.DS#b?2O(^p4A@glO,I=/gP'5t@>eb%AT#wI`N#5`?*%AY:$-I1R`RKa7l(#?:'#-;b#v'`$s$-75>##E3$5FEuJ(\"\n    \"lh)Q/x:Ls-_%Is$bp*P(g.<9/O<Lh$Z%Fb3E@_Z$7c7%-V.pNO.Vg'+uM<T%O[FM$rsaI'rf9%kb_V8&m('f'qc9%kEIEp%ESXW$]IUS.@tUB#'Xns-[9[S.9IlA#)F.;7NC7X$b:3E(\"\n    \"FcW5A/`KasFx86&rctqAT#Zn&2HU0(:LlA#o9]Y-3qHL,?AQ&MGcn3'w[C$#*&>uu;[Pf$@a''#2jd(#cO>+#=gb.#]/mQW2%x[-/H+G4`@_Y,]crk'4Ta'%iwhWh2O@lL7]fF4o`[@>\"\n    \"ctkA#&C+G%,uVE4^8d/(JZn4(Xvk7%LARv$G<uD#^IcI)?]d8/3(BD=>q;Q/K4pjK@`ifU)jC$'Q<C,)(NGF%Ff'iBup2dM]EA@#]W,R:`0W`N$Jx`tg5Pw1f^hV%lUU>,W.-SmG5&Vu\"\n    \"5A1g_;;o*`.sxtJK5N$5X/iT9mpeS'%0;3=Cw0f$,qF.%50F[#bu.1(Zb5F*>Ne$9hWQD*S`R0(mq8uc;5*i#WJi/8Eqv.MMOWul*([DmvPkiUIfgO_I-GjBb/QY-;PX</*HDkNkk'##\"\n    \"VWj-$;_w##Jd=8%OJW]+5dD'6&:ZV-/P7C#r4:W-#EPA#3U@lLb56Z$rfVbUVKW+))m4:vHEX=lf[5:vmUQei4i2@*uMA=#bwu--&pwu5bN]:`jMl8M>8f_s9Id)#%&>uu%hUV$YqB'#\"\n    \"X,>>#j::8.@Oi8.K&.&4f#o6837AjKk0Vt6Z&PA#hg9u$F0Da4px*F3O.rv-d(4I)WEq=%M,#PS'IjPbPus4SQq&KJarwh#P[HG>9H,29j*S]FWKbcDJs[A?49SI#n+^4SQ_k2##CqfC\"\n    \"[++^f]jt)fj.:>JJSqJ>#fpp_RF#YRC/UJCkPE#7*;1JWmvH4#2*s[$#&5>#Zu^##x/BJ1B_co7^/Vq)aR(f)g`*i(n/1#$xkh8.+cLs-xxxiLAj8w6MJ=l(?W8f3]]wD*.%v,*Q35V/\"\n    \"YE/[#k.YV-A06l1[X>g)^^D.3*57X1o1x`*s_J)av'UA?(]`h3#DY>h-(Og3LqjC?1*TAaam2`>UA<h#ZTF'MG'CbZT6_ETNdSCs2dRCs'+'PJYNs6(ub#&%Bs[K)MS0xt:*+tYrd+e3\"\n    \"]:oDS8kvR0[pBxqM#eV$9?pn/-:D<r-%$rb4LE*V-XrjE@U;su'D?_#9kgXBs_$L:;Fp(6%2PuuMQ&I$**^m%xndY#B8]Y,Sg'u$v;Tv-KkRP/JC[x6GHuD#j`5J*#2xA4=n&.$4G5Z,\"\n    \"SK]@#PL'02RAFgM4]Zx6$VcS.C=[s$-uU5/qSID*:'`hLK.-HN#<[]4G$5N'&%t9))QnS//Q,T.UO?S'#xK%%BgEtC*u@X1<qOw9n#gD4jqw6/Zx3V/Rg^I;0>cD4khI:.'lR_#D>s<1\"\n    \"fGAh>fw(73Ku-LG'`:KMHL/[#oqFgL:L>'$aL+c>mp[RQlEig%#-Kl)e?'X'3nE6/`F1lBSukFTdkTxiYh16&X0D-M4Wvg2ZH^j0EUKq%)Ab61?]=U&qSQR&ZLVS%N(^2'oblZ,c$;=6\"\n    \"4;n7&Dg0e;U15)4V^k78knWD<70FL)%+<u7xI7g:,cik)_J.L(uWpU%=f(Z#3%I8%@'gM'j8G9%i70+*Xhi;$Cke@#Zvp2';F*T%D@#.)ss8j0`=ofLpo>n$Rxb;-_t`;$=sqL1t2^[#\"\n    \"NZPN'#qYJ(E6TU%&OuQ'M:DZ#WHkt$1O2<-bkxW?qHQAOY)vJ(@(m#@,UHo'>S4Q'Gi1Z#gm%5]?=c9CYPZJ,#*#lFp4MC4JPej'nn$t&JcZ/[tNn5GH,$4m0YuG4<=B*uIiwd)d@.FO\"\n    \"WmWE4R;)Z-Yj^m&o48$$3fL;$g2((,$>^F*B/-@-,,;Z-QFft1R7_S.%vnh(^*u=8.6iI;djUb,9Z']6V]Uf)4&V11b&?l3`M%-)[WGN'PsJm%$oU,)8xj%.J6a%,oi'h=:#3l*Pb)s7\"\n    \"9DD;.rd*g=tB(R)^Euk0`oaB4D;e&4Nr.3Di?A^5@@Da$ofUr..-Q,2^o-V)*J/].'Yg(>f+*K*+U&'PILW:2uU_CG^*wS'IQSB5DL8j0GcVL1HUW:8n<(8#%/5##Hg#Z$4$q:#[x6V8\"\n    \"4XBN(1d(T/U&iX%'@t(3[Z*G49&m,*_&ID*(4Qv$6Qv?.QKZd3d^s/Mds1AX-RZd3=U4mu/]29/ESu>#'Wq0*:5*g%Fg*]%7o8gL:a@.M)D.V%3=@sZ3J^&=HCHE+v_v7/]9]nLk0vN+\"\n    \"AF5buDb)+O7SIA-=xZ9iWeIf$PSv,OL--05x.?'9:h9Dt7j;B%N=?>#1fb+DE@(gC&-&##BC)?#L&nD*n,U:%Z(U8.'c*w$p^&+%r;Nv%x:.fNr$[x6%c7C#5o68%c3hfL35`[*:p?A4\"\n    \"'2f]4[#[]4A?Ea4b+E1'b'Vk%N3B0KJRns$wJaruZj`X@(mSf&MXWT%s2$E3OBou@6[UPDAg&-))x3W8(4hj(-H:q%ZcRP';4n+2@P3Z6fh8@#^jTU%9wVh)^#md*BXBx$?=q@gR=IP)\"\n    \"Dme](x=rY$-vdE3l'qh#i_3ku>p*T%YHF&@iA1)Aq[#%A'g&F*1=99&^;VK(iV.5'rhbGM;t8Y>JA/?0C..w#s(,u@vK#H5'kAR/*fM>P05YY##&5>#0GY##<V<PA;QZ`*[G%R/X_<9/\"\n    \"&MU8.t0qS/R$6g1fi?<.j,wD*RS,J*tI+gLrvgM'cCSfLx^+X$]n].*KD,G4/wi.3$LIf3Kf@C#vE->%gw7Ed6b#+uA-#N'JQ@5;crhv#ovPN'LLhY$EOnW$C]Yk,<pm8'W0=X$[)qQ&\"\n    \"so8'+dgh,)%]ZoBLba52qhw<$AJ[8@g]UD5Zah?&$:MN9'$Dv#iLe#oN9d2(IK:,)hEow#1`R7&xDDG3$riv#l0SO#UmQ0(Q0Tm8ON1g(SDe-)B'K6&rgZGGdI*`?LbaP&w'%%$Zw:I,\"\n    \"@+iv#Zb2$#&5>##)]$s$'7###(0f-#9->>#,W*i(wqq8.sfEm$6g&F*)>WD#'<Tv->:2-*/7?[5,FYI)*)TF4%eOv-9O#,MhIPs6dim;%xH-1,u4YJML'8;4Xf@C#Cm:9/tbg/)k[i8]\"\n    \"KDb6RSk3D,#1I>#*@C&5vENK;cGO/ddC2,TopR$.U-t*,Wv=*4ArwC#vh5)4o^Y>BeZ[c*VK]coA5b`+&lCZ-065x65JPg3@-IEN#6&BLu*f.%DN7subfuXB<mA],S3-FuHXM_,LU]$A\"\n    \"*we-3H-;9CB8,Z,'Ve7ni(V_,NQWx,A@J7n'KXY-cfRpM@A(>,sqaUmL]1%6)pxJ3#%,44#36>>YKe.:IDw(<-(35&x[k&#2GY##xB>N02Vs)#FXN1#`+O$MS)B.*86YJcNoT,N;4Vp.\"\n    \"8o0N(X3etJEx;9/XSNJ%8cK+*I5^+4OK+Z-=kiWJ&o]L(3'p8%?@i?#ax;9/Y3Zt1d&Mj0x<7f3aGUv-YiWI)p_UItGWX;.+.5I)A1iG3^12X-7(it:@oGj1XL(KME=/GOtZ6#YM:2+G\"\n    \"h&HAMJ>&`$_+vW-C5(+%c5rFMYY--)^<?d3ktHo1W)m40uGMk'Ln<9%<P;/UZ7Um9#sq;.v&B>*conL(u(*=.3//P'f%k**Pfil0o6-D4<d,S/*eKU%YD@L(I0<`+J]M9/4jdU?],KQ&\"\n    \"s+'eZ7Zo],J^%)1*e6-3asxx,?<t^,7(LF*KF.W$I3TQ&$=d(+vxIfLQg9+Ga6JqV>YOg1EZ2%$a=Ho@YlI%-plAB+Ab$g)l`nH)k$Nm/eKOs4Bx#&F2s8'+QfMp/C:-lLC$r_&PdlN'\"\n    \"83o],[,1;.t%SL(^QKq%eO7Z7/rK+*2S4m'W>Ea*JpX>-wP)o&o^b(3e&67&U2*E*9JY(jH1/Z.lcIh(%jNU09R[-)t[^F*rx<I)He<T%X0J%#1xL$#%DUr$A=,##]Kb&#XbY+#l:w0#\"\n    \"q8J5#%$-;#k1>>#TNb&#FcLu76&vG*0(#hOhr=c4U3niLZ(RW.t6]8%?$.-33.5GM[i)T/-vgs7.OYH3,T/i)MSEF3-_qk$#ir*49,B+4noa.3Np+u-'i9mAIWeA,6wnU.r50i)XvnY/\"\n    \"PR(f)g>Zv$%4Ag)i<Uq)I=tD#H,jhLFRcGMcrZ1M<gt/M9-)].q]iD3.:bZ1,dob4<q6H3k+KF*EV+hY_]d8/oYPLMTU#5Mr*elL@SR:7N:fHdL#9KMs`Jf3v$Ku.&l,_JJOi;-.(2t-\"\n    \"+tUhLxTXF3J29f3e$X=$90Ea4T[t>-tm3r7i.xP'p$m81VqZG$2+xh(T$OT%E^1O'IN4>-m$BQ&_KA@u1<-g[*E:due]uou)MLw[+cjE*VZQD*-iX.)K=rv#]%b**Y5:8Isq>2(RJW**\"\n    \"O'96&+E5W.moK;$+>G>#0Pl>#Zk7[#RhmY#a3c/(ErD^0)<xK)(kA308*e5JQLs+Vue3O#S>71(*b7a+9QWH*oVrK(oS`Y5UXE$$_Fl?,(vWi(h0830Msg#$o[^b*#qH-3LkN9%5Mc>#\"\n    \"?ncc2nskK1/i.@-v.+**Un%[#)8G>#m3fh(LKuY#MKG3'aSw.)<YL;$'RR=-,T.D*UvQ]ex(loL1Phlu_Cm84,]tI)N=V?#Bg+1:c,*s%ik_<-vxIfLgTZK'ccwH)'pV4'^=$T.<_D`+\"\n    \"15YNFx)q^IxwPpFUpFZ,(M=.)M2IH)mc.1(72,Yu4JIcElNKY$H&n)*Ps?J2t`tr-ANuN']-[DEi'LR/NFiZ#J8YC5EQcj'Us'1)rQ=x#GQ$7&YEbX$NV]^+=(eS%ZP[-)bGB[6[0qI)\"\n    \"(1D%,&Uw(YBK03(iHK6&^J02Fr4e8%G'^m&=XVl'cvNYCr=Pv,^.^'+2fL;$xk.l#f2?r%L''q%3c1Z#*tNu-Psu3'F8Y#-F'Z,C+8_Z]4J2iFCE*9%oITF*CZx],)`P(+T&uY-%MJfL\"\n    \"XQ<h##&5>#-Dc##O+LS.XT^`3R4K1(3=+D#T5Du$[fv8/(S/C4]NeG*@GUv-]]WI)N5lf_'Kw&_&vlXc8'+DrW@Nmu>[PiPmRa9^%lvpmL^bug`7gN#Z;*hY8J.XuE(aVP%Z4AnWreW#\"\n    \"7):J#QoMx^a62sT]%Ujug$[V$eRZ3;dd/%#r2h'#X*+S(#rw@#jKPJ(bB:a#h=S_#8a)F3?DXI)WTb&#$)d;-5s=L)`pN#FT@qo.]?L-5^#^?Ca'j>U`SV,FCp4W0?No^5.1^U%U>FI#\"\n    \"f]GFu$[vVufv:ONK4[3F/>$g#0Cd,-qDN80AwTS0ZB7qVi9@###>_7%MB5##j$),#YQUV$Jj:9/6cGg)n&PA#(cK+*BxF)4H)TF4[C[x6mm/R/Jc7C#`]J,3TQO;.W$5N'B.^;.i#c?-\"\n    \"?:2=-N=9k$0PsD#+<;[01EQJ(2`*D#Ph%d3ef(a48AEY.$:*Q/dFMX-+0*F7#2K+*wt<Z6ZDsI3&LKp%RxC;$5lfF@RvnlT1Ynm0*H5>u+UlNBTH0q%2w%49U5487+CAs8Zor?#XNLw.\"\n    \"lh&7&ti.?5F2$a=$bb5&.-2e/9'4t&v17%JYYokTCp>7CIq8Q&m?'JN%hOXA>XnW$q*du/:PlY#Z-1H6ncu4/gGUZ-RJLKCmd+45Wthu-Z_wW$-T'Z-pTKm&EM?N#:Y^Z+%4'q%/Jba*\"\n    \"pK;N2k.X-EMZa1)HMSduIQC,3dF9/)FL@[#I&]*+rN/h389]9$%O<D<#Kjr05lD0El]E&+S7*Y$Y1wo%u2@,=Z-(kNu4VW$EJqpAxLi>0g9tT%/:jl&CIX7eo.tS7:nk.LU`Aig#.xi'\"\n    \";Ilo7OqerHS7/DW?.tX?`eb0NNebF3^q[s$@=@8%=qBd2N9K:%xt>v$-CJp.lTnF4nN5Ls/@Rm/N5^F4CV*f2.Gpn$H:[x6FQ:a#sbPhLH=3NMREL:%.7Om/h_4V/%bqk1g9^Z.mHW[,\"\n    \"ik6mL(FUF*U'D.3lEA5/.LRI-*47m/0?6N')VEj1.Ow20WK]@#_R(f)GmxB/H*Rit4O@q.OoX;-U4fw'maD.3&Y@#6;n_aNZf-<.uiWI),5*j1lmd8/5^-@'DwhhLt&Ol(-Jns.:'#-*\"\n    \"829f3@;ClLYOj?#BS7C#I[nLMCIiIM3r%Y-[`.XLpVSv$0dS$9%,^v$wCbcMK4&+Od4Ms-?\\?UX:5nBX:Cp0j(,CF@9fP,C/7kHpIMGMe?_g2V&X>W'4^FvF+Qf`>#Y(L9A<bJo/`Xr?#\"\n    \"Tl]B+<pqu$18G>#c-.&,@&<1+[l7),IiXjLW<Af3ruQ;%4+@8%I>ea3BWn([.m(P0p)WL+6gV0(Pf/F*>rb.)gE[A,BsdO*,>5M(An5R*G-uB,fuc6<wl6j'$ipB+^1%<$7`M50p%O:@\"\n    \"3T)4'qg=^>++EZ#O8K>0N_3>6#ELcB6OJP#_u@BoE-I9%]Tja*'fNT%$;#NBW<WP/DX3TZWMm?&NRP7n*WP7nT'srmPP1KCe:4uu*3a$&CfHp%15h]+wkb]+pR'^tAG#P2#10DlJxgB%\"\n    \"7]4<P-D/M#84*C630;^m$cg&Of[j_oVtf=u&+Y4=D`0b$%BG%bIEpZ.je@7a2Ge*.^FJOMMs[Qk$#Kg1Htni=3<KmS^@6pjOKxfLIraF5DGUlLcf)[$H(UR'b#iG)RdG=$@::t6-uc+>\"\n    \"i*W<-69NL)#i%@#2'7L(+T;K(dG(C&:wu31#2S5'9'Sf=cnKdM^bM<-k`O;-fKlJ(Ue,Z%M&&A.f*/t-;W8.*fR6U7+64#-/u8E#.a5F+7a>01UGk:0#Dd0'E/.M18`j0(2-3E*;WwiL\"\n    \"3AIf5Tl&l'g,0@6'$Dt%LDxl'f(*X.N-Mv%Y0H`uo4`;ZdF$ACA8=b%3MV/UPWwJJ4A-#,1&'q%`.C(j&svCpTE2NTOB.jI-v0&+*W<p%BDe8Z0YH(phfjp%Sb3rmZM$ae5I/h$DhaT%\"\n    \"xQC(VK%X&Pn$g[pTe8032E*AWWr@CoV'&ZOsn)@=Xxt6MVO0kl1`:F%#l_3ak/XG)e<Gi;eW:Q&BcqUUBW<Q&n8[c=pj:6&-VapEb9s,Ub?_<.6TcF5X1LGF+lQS%&A1;$ls))sc'el/\"\n    \"Qss+;6j7JC>m0MTn8*A-h5@D*V_[s$9@i?#@FIP/r2+G4g3clA9MD-*3`<9/)7aV$CNO;.gJ=c4_l_*4TV[Z$]I.[#gYYx6O7bc3+%%],P]Ol(>%vr-^4^F*ZZ*G4,B-$>J/4Q'_I+gL\"\n    \">eVa4Ldw*7EC5s.'-jGM9P7C##x<v6,WpoLn@>`smL2;p+6Og*#'`=Y6e>K9O@p@OTCxT%;K);pHHaA,o*8j0-mE_$[*s20OO3:m_E#3'2l3n0s*Gn0O<ij2&<dJ(mxjN;tIw&6(f>RK\"\n    \"1hQ$S&WWD>[5&b6PhE;$s^=x#O0i/)X>w-)'8sL(<<N&+&?rg2NHkv#vS1P0Y4uZ,98IPJdVps7Z$fs$0*Ne39N4q&-T+B,$E1Y$fNgs2ii$)vjh5su%U%r%sqfo@cfb$^:U#fq[oAS'\"\n    \"`7:W-k95j'NR6G4X_w1(OhOv#k6I(+1]nQ0Sc,&>8a>,>E<?/(E0*o>_Z>?okf^f59q9E#LU.hu9[G40F/$)<SPx-):wx2'/CrJ3/FW;$SF#F-,v)S&qIke)Q<A&&.`Y$6.mtp')gc'&\"\n    \"3Kox,AS-8/p&U6&(AP##9hat$YP/=#r&U'#<2<)#h,>>#]rS^$*)4I)J`?p.ZVd8/NHHsgfo+G4H`NV?CD28_r'P5Alr:pAkew8%4o+'.ej#M0eKQ@-5H#j9<o'QMti&SMmPf'A>g(A'\"\n    \"(+%RR?rj^-t<)%9,(UhLGxdMM3gfrQ/`F&#<v3$v8kE=$D86;#%kP]4^^(g%I`#V/1_Tu.uxKi)+=H:74%`v#$DXI)747W$j*x0$20t;.<<UG)G_.s$[Z+&=k$'r.M.5p#xTLs)*md,$\"\n    \":v+Z#]`X>#_AjY#m;T1T)qcOK(45d1S5#>uf?Tlo1Yqr$2Xx.(soIJq+,7A4e%m%=09ZlA+]Lv#9Z[V6cBeY#9EsI3&L(E#n?XA#N#G:.O1)2MRQrB#Njhc)Z0m3+<8Uv-GZ1T/ZPWe)\"\n    \"H;d%-u'kD#%*YA#K5TF4``Qv$eIfm0*KrZ-k'4]-bI*9/&XD[%<8eX-BwO?.WvC60g>PL#'VrB#6l<;1IB<J3Q6s@,T.P2(f]gI_WGV0(sn./1DnwnXqEjc)bwM,gKTW.).Pk]+Z[$5]\"\n    \";wG.L_Nke#e4XPAY=14fx:e%'Y)O1^hTKD#R%Si^,ES>#&4.J_GPr8CV@/J_fM5tNTB**C_+$v5M@cR#(NZp.XgA.$7qrY#b<mr#b(b9rH]bV-ojnY#Fgt+MXYci,bV5L#4o?L*kaN$#\"\n    \"m,_'#V,>>#UkFJ(Y]OV-Hfm4(Icb;-Q,r0(<Nb>-]is0(Z$w9.0^k-$cVfF4l/^I*p;N.3rGU#$tf?K#,Gluuhp`suEL#juh]oX#rZFU%>%lOf28e?j(6ki0)Cw=>`GeOoq$p@##$fh(\"\n    \"TAJ[t&gfXuP=T%OLAbtu)oaX%82Zxk5l(v#'CxquV1/$jP2vS#:^ZC##u+YuXSYF#_CDl*7djQfH>D0#u_^>$KRJ)+x%'K;cMi+M1?_F*V_[s$9B@.&_?7f3LhwLMqG]s$W8h*<'=Wt(\"\n    \"8,l4<^EA8%B-Tv-$]K+*,,6J*x&`;.wl+4%==:4+b9mS/5H+wpSf9K#-18<8Q#ssL,9N,]mU)XL`'u2MHgBSI-D<?Eq8+PE*^$FR0$ZkFui0iD8W;iITElUIAaif<i**W7d_M)R&9%MX\"\n    \"Q*^8)*ftG6>n'&GeJ7m:^WU3M9tL$%EsYLKQ4b7Rdx#<L6BZW8kZ458'/@:WOT3)Wp/$:ME_o[tgLRc4v2`$fuQQ8N<keTucKM?-a7Qn0eW)</63;XLi]S9MIC-b>xZhM:UdZ$>RBI@%\"\n    \"%P%(#ZIJK'=O1hLuk@d)-AIj09Fj?#BkY)4iVp.*?C0T%3pD,)WFn8%wO,G4-a0i)(@n5/v?]s$o5:#$NAf4(ed;?%<VhiuiDBW$)I&`aW;fU#ZNcHjM0sR[.G/QD`W[d?XElY-6]k*Q\"\n    \"`vB)h3jQY>`=^,=6iiEH^.a?-cZ8P<Ac]>*+#b##N<<L#/.9?.+<[<&F$3AFMF<2'B*AuGA@E+iQ$((;$mxIF>ZxL#q;)P)J?@g)dBCa#0S>r8Z%-n0B;_+%.`h4(qAhQ&2N5vep7'&4\"\n    \"`PpJs4u@(#Uhc+#o@058['qN(UPOV-ba^u.]]cj)EYUv-i4NT/9,B+4EI.lL+o*w$vOK+*-7MH*=ajU-Oci:%@7*u7[$[)E4Z/i)*fmS%iHYIqCQa7Rhvv_s0VcY#RXE2'#tc(3d;Ot-\"\n    \"<>l2<LgbkFxm6N).srx=%@o,jXDVculEY>#=(4B*JL4lfT68t4>RIE+jl#-KZ+VM<Q/FO':Hc##L4T%OTf0uuOF=gLg>i`FLIWM'M;2.L'[uJ8f*.EXZZsI=wIBV%rngnD>.aFi=m@Y[\"\n    \"I4+0jm.FD35^St44eSb+eOcf.,jwi134ap'#pu&#w:@v7)FHg)W,O/MXT,V/)F9u.Nn`$#/2E<%_mq&$ZQHH3>S<F3B+2mtt@W^uYE74nV<XaC#;dA#A'Ds'3s)W#vMS$pjh]C#+K&9Q\"\n    \";Hl8m5I'm%W,(nLr<;8P@+6(f)lD+ic=].q8,0Q_GebJ#1OUBiCd,X_iq@B#taVv80;4m'x2Pm8CLkM(-8r6/Crbe)RbTfL*1OMKMlcV$)55>#KL1YPkjfs-8O1#9kx,lh7J>rH$6BrH\"\n    \"$T/xtRCT%OUl9uuPF=gL*9<J#K#V?#-RqWk%7-fh+wj0f8ADD3oQ5(s60V=lxC>tU(]2t-blZh*P^Uk0]/Ea4hBk]#t?(E#AKmD3iB7f3Ev@d)dWX=$+SEF3pe4`#lJ_5/E]DD3-rY/C\"\n    \"30h^#]hkI#Go=J?WI=W6IPwS#+7Wxt@E)<@=<<r&9Ig>GxJrCIpn<ZuiATib1BKA=vdSibgsO;`DkuH#J2=*K-4mG%M@d:A9D1p1mD1Ft,WdP#/&Ri=l,=U*(](S8$K3F6$gQAJon5wb\"\n    \"d=OA#v[9^RjQhOH>0a,?2n:H%1GDpL/krr$Zg>N0Q3=&#8&*)#;iWs87/<6LUC<9/`o%l'C.ET/iu4c43*j[$>Si=.B?lX$kHSP/l[o=%U1]d/4KnL(xR[Q&F;`Tn,Rg+rCmQF#$3p.U\"\n    \"7D,LPDEj*8BTDW-C%Ro%Ip2Ab*m''n=;-`Ev--VQjDqUW.up56J80(U)7D&mqD>&#ni1)2stC.3$DXI)v;Tv->=J79O-VT/@Dn;%,aFaX*_,S7-u6?hw=(XL*Fn[**Z/IAVDT+4<k8r7\"\n    \"j4vOlTM2(^-V'0fB[BQYJ2B.O<nb3V_)PfL4C:p7SAw>6_>Xf:)(S/)QQ$01Q-Tv-bp*P(QV>c4/6aQ.vNBD3cP>H3J%)W-:KMInJc>/*qKA[u0E2`bcpY3'2q^1pSIMZu>WqN'vkIoI\"\n    \"o)GoIF,=%q>C[&,epGo)40H_bW3o[#;.mN'*xCT.Gr[H#D8`T.#N,lf*q)>&o&'%#ipB'#sa.-#t`p_,K$Jw#UAr`3G=<u-s@O.)iNEH*LNXA#`aJ.*#MFb3Z6;GD]Ad;%XT(p&to<W?\"\n    \"M2tdX,9'j0.w:i3$tC+=@5JT%Ia;I%6$56'>P*t72Gc>#0.>tVQ.D8%gk^v7c<QnW)1k;Waf)_8qp=6LIp^oI/VsvEZxu(5[LDnNN[[UM)vl+4DtVGM2$oOO6@f=CO4JT%]p(`aa6s(E\"\n    \"t0_]XSi(d+,DY>#=ZG20@3lmW-[tZV[iV$9rj46LH6Z'^L/`@LL>c<i-BuhP)R0RE3dc(5?H7T#K^@:Mg[*##FCoV%W_H##7l:$#K_R%#`9F&#t,_'#2^Q(#FPj)#g[P+#_V_B#$>JL(\"\n    \"eF2.N(dC)3?2'gLLh,:@aUq^#xa96tu1A;6%YX&uJ`M)SnJwUQ0lO]uS>;X-MTP=(JC]_M;Ls:m9e;w$#J$s$+)[o#`DT;-/4T?.E:&GD(0[-HcdHb%k^gdOj&#t$q1,>#lUs)#2rs1#\"\n    \"9AXjL3cUv-A^<c4k?85/'/Us-B2Kc$S-;s?e_Ua4P[7x,F-ct(TX#W?\\?vlG*;%720F%V%6hOWD#?Xs-$n1(kLthQ=7Pj`a4`4r?#'8wK>$7&s$ru_$'BiEX(G(XD#]=:8.bJL@-EuAgL\"\n    \"<9MhLbim66XCC8.w8.,rVCT@OU1tM(cf8h(c_mY#d-BT9[vm/(_Irv#aZk,2c_W4:u5<M2k]xQ8k;m9Bw5q<$<rLO)-i1)5<x[Q,(=7A6,B^],sX5.)_Fh2)1g2W/m[@A6(1;A5A]u?,\"\n    \"b]E0(A:`;$_=GI)@qPu%'7Z[/UPW0(cJ5A6W*7-)T,3,)gOUX#$ViL'>kw[#WAdV%:owC#Q/;8&q]d/(T?s@,-xHe4veOU&OiOv,qn)30kwC%,N:>l*-8i@G#=pN0qp&#G)Eol>A(>D#\"\n    \"F5X'Gwp.G>HV+>/Dox9&o(<X(j$2&5h1UP/T3J>#G+D9.>_S(#P[0d2c0[##Or`r?<&=fhY'3:.Jd=L#L^?A4O,k.3OW#A#q)YA#>lsY-rwsZ6vuGA#=Fn8%kc>C/29kM(/+WE4;5c$,\"\n    \"Wm=A#li)U/DdJ.*$H/J3tDj63ND*?8CT=D<<[IU/7Mh@63h'a#CYK+*c]]iL,N#<-Vc+p7ZGGF%)xd2(0Sc3FT`c##5tf$Tpwkj1&c7C#l?r8CKJXJM_.L+*ojrv$ACI8%p/EJ33Du`O\"\n    \"@ril0?Y1v#;['E#-PC;$WYBa#+]sc)pCCp.2P&S@DmIc*PjYR&MR7w#@ksP&S$HGM?@c>%s^12BsVhC#[ZFVH)DD=.ZTEU*YghG)`FrZ#M1-p.,;1[,swGi<t$H]>rG;50V)2L1Y>h)?\"\n    \"-o_l0Ha$W%7J1A5GdGu>Z'8/1$pH@-2[T31S0pW$Fr$s$Q+Q',=4@W$6w?O(B5^:'BHeG*2l-s$_kbD#<Gd]u,S$40Q*s@,?,5>#2x/G3A8k@tXhU)+lJg=uaF3p#cI4gLt1LB#N9XT%\"\n    \"C78u.M/Pu#@_Am&lIB+*WEDt,'hoN0i+`Umn(`nE^$[iLK.gfLj@gI$RNY3'0P+W6k=Z>#4x$<$i-Qg)lK=T%C<1p9$1s(E&x/T&;)%f5%_VN(irCv#SaKq%3%wX7Mw(H)jF-Yu[S%;4\"\n    \";X>`4=GP>##Rd5/%vZ7&Y#]M1b05j'-Gc>#1oIw-.R2)+27lQ'-G(v#M+WP0kCm]6Dt92'IJWI/*=q+*;S5##=m$K1b-[##Q.AS@S*m7[*J#9K@Q/J3NtRpKnOb'4%[*G4woq_,/h_F*\"\n    \"N$n680euS/pBtR/._9:%@I.[#/sEW8^o598mkj/2S2ic)N#Cp./k>A4n@A2NY$wLM+oT&$GXe8.O;^+4tsq;.NXPcM^iXI)%V-iM^M,W-g_PsSO+p+MP6]8%w3D3,d`I:/MBbD<8.`v#\"\n    \"@?cx#Or4$,.:o[#e=xfLcGrH,Iu?s$Vh'L%$0vN1cRht6Nn=_PC`A#,HPC;$7C*T%kk<GV[8[I)YIL8.s);o&sfE6fX`nW$.c[:/EU@[#0%Is$cF9quivwd#8%rV$reY29tk$T.;o,p&\"\n    \";ipF*n'=5&x6P>.=RH;Nm$dG39QFQ%PAMq%2=WP&IG%_u`-bw7b[8T%GpuV$4SG>#<04*$^1)v#ZvpAT-Wf.*CPlY#C]HS/d_=<$]7-Yuia71$4f1Z#3,*5A7%DZ#oGM,)Qgun&0_v5&\"\n    \"Xn./1TXWq.d3F]#thOgLjZ5F#;Fws$;Rn<$W@_1(D%*GY#MXm'Y*]@#$####-p=:v[lDw$h]5N#mrVW#-%`Z#xkQg#42CN$8xM[$rfl##14n8%*j:9/,ZtlV4[tD#dDMg1&_*G40U%],\"\n    \"n1pb4wF]fLs<]s$d[EH*6vD+3WAc#@Vb6lL(dID*GW$@'_v`$'v%K+*j@p^$';h;-e4:lL&4_F*7qjnL%umLMWKihLef4_$HRl3+HpgDExM^T905J'.1O?IMZIWY.k(TF4Q[GhLu<Ie-\"\n    \")o)IH4DXI)BIR8%uc^,./S4GMJ3f/M?JrIMJA9M)p>?A4g@2=-7Gp;-e9b_MN+r]$(a[D*Rk@W-*IR$9l9T9VHq[P/l.bj.`-xP/e:9K/CO[8%#15GMDW&7.7Mu/Mo`;Q0^'oP/G#;9/\"\n    \"aLTfL?Iau.ep5V/>3NtCHR,gLKlR_#:C&s$(cd-HoP=j1GVK<T@='c3wr];%2*Bb73xdD4c]8GM9bsfL/wlhLwEdD--iNB-nPn#%OGgZp%k0u$66RK)O8u?0v1$I6$-VO'5tT&$*V/)*\"\n    \"%bLG)&Xjd3Fni1)w-ikL+7@e-;(5$g3'GwTulAv$E^@9/SnXF3GF%lLs^<<%OwKwKF*`>$Z(R,*VQ+?-7>Hh-;m7nNH7Iq;Y;'U'Ve_q7w_l8/uNdcMZvf:/hL_<L)J+gL,M$A/N5TF4\"\n    \"EF%lL9Sp_4w@v`4CMZ5/@bp:/e_kGMfk=c4&H^D4Z[,^#i[iHZjlOjL=[,[$Ae];8vUbA#c7x^,'#[]4LHSP/fqfc28[b,2YcD<%^Px_4@]rY$uJbL#S#qR/R6m3+n3MBoZ.Sh#3U[LM\"\n    \"(&`1.eL4gL7d*Q/bMSv[-iYW-YQxjkB>GtLjW;NDw-L+*$YgBJ^[-th1jB)4lPf;%4oEB-rmIJMcsW88-*+Q'_q#qr)F)HGbf+G4xgaQ'eF#v,g[):8V3Hv$K>DmMx0L+*MUPHM*#JnM\"\n    \"7<sk'bF]fL,](p.iP[]4,_3[97u+gLc&s:8U&d,*-%G,M8mRD*>#:rAKpVEe0C.lLDF5gL)=>A#uFuZF6eu8/::Ox-B9vv-Jc7C#J(i9;g>JIMC#UgMYmkj1D*)iL'7S_#Wsf.*s`[D*\"\n    \"UO?S'T,H;%]0N,3[t_H-WY@Q-$t0<.a4n8%FKF1L(FZv$cBsJ:.cMmLCM,J*W-vE7/$_)33)=9/x<j?#rKa]F*9Z;%1aO02Gq[s$v/b^,XQ46)a'X$N5+uP8=^h?B6c'gL&-mp8,QY8/\"\n    \"%,*Y.rYRD*#tqtL.XlGM)rvhMin%s$$Ias-PUmLM&tZ1MOTbn-SuRn3F'r-MUXlGM(X;E46;dH.MbFj1.)oA#/=,1%EH*jLe*NT/+K)[KunXF3eN+Q/NM)Y$^RIw#egFa4:T4Q/1(5F%\"\n    \"IJ`)P,+%Q/aYx_4=Av]#I2lm'vTr8.^&vAQjJYA#XtCE6S_%m,UJ=c4bxn+MjPW&+t@/l'goXv,f,[H)2'gqB^:4[$q)mM;^9f3FE1Qg)#VBj(5i`9/5AS*-o]#Q'/PZ),M?^m&LBpM'\"\n    \"9hpA?U9E)+C2>?,q4K/3v/s'>8'<h)3*p8%mB*:.pd[0)7x#V@]ET2'_);4'l'SJ1,5,S;[j3.3R*^M'wYE&5<5*p%RhET%nw_<-D+RT.6GIM1?O7[#1]lY#*Gc>#X^M[%T8V;$]]f#,\"\n    \"3SP>#iBNU.MrCv#LL39%Z]3**=Fn8%gYQ$$I@2Z#?f_;$91iV$]xo>,5+%w#MfkV-d#Lu$wm[a+%rtE*('<H*+,ES&e[W5&MEbX$1TaE*Jk[S%jOcV-hJ%1(DfCv#<Rew#PR%<6]T,3'\"\n    \"D-Fx#Kgm`*ZYaa*A0^6&51rZ#Op$H)Jpq,)KLi?#I5WA+JB':%s#Zj'1fCZ#?>cY#1u-s$=a,l0QuXZ,?F@W$4.e8%>7wDNO$sZ#Ewn@#4rh;$@-cJ(7Csl&E0t;$s4UH4IkLI,L*@S[\"\n    \"T0=X$I]uY#fn6=-AL*T%bg^q%NQ.v,J8?[-dJ`,)oMd;%Ss:,)jhl$,PNBY$&Y:%,&OO=$@$gM'fNBQ&OHbt$6:<p%.M1v#H90Q&CuC?#J&@H)5=es$;mU/(m)UB#?]8N0V.+,MP7@s$\"\n    \"M#ik'<Ln8%2(Is$Oq`;$@Z?)*<1Mv#;C@w#6@,**o$PgL,/Cm&cn^s/&T1u$mJ7h%^>P>#-MY>#-SC;$bCt2(mi%p&QvYN'gDmR&m&HR&6l1v#D51Z-TLd>#Qp_,)AS=I#ahtgLGEZv$\"\n    \"J[Rw#*P%$$6FN5&0DP>#fGjA+2r-s$UZ1k'a$It-%_ugLwOSffL[jP&dQ&V.Ttw[#9;P>#GdUK(:(Vv#imA;.OtxM'r'DW-SGRL(wi`s/;IcY%-g@H)&1D)++Wvv$,xc_+($9j0Is+Y-\"\n    \"J^^V.F('u.1L:k1F?W%,nkcZ,VuVT/[H&*+H7PU&$Z%P'gZ9^#k&:H2;0bV7O9B6&vGiG)^G%h(eg44M.pch:g#?n&YdI<&/F-l1GWHR&KVv+<@hk_=Mx1H4OJ+a*<jox,IdpY$]m(o&\"\n    \"D_es$pu)S&UZ^:%te*T%c7YB]<tq,2ec`s%HG1NCIq5w5.i7L*:e8Q&E%D;$T*pM'btCD+`%4.)0F#:&d7@7(5u$s$wQRt%lo6$$>/?8/cFofLru,x#.c_;$RXs5&H,3a*:lc>#DOWp%\"\n    \"fLGv,RWTq%v_L_%eu-W$GLIs$7_J2'QW-d)F0':%R@.@#Y15?,D@vY#<O3p%A=E5&vGLd2IRiv#/SlY#2OPgLoex<$NXpY%k_8Q&-PuY#p4u;-X'+T%fKjaEq8qJ1/Yl>#-q[g:Wcu3)\"\n    \"MjDK(I=V?#_)Q/(FHlj'wC_0G8YMq%;l-s$C*0q%=7.W$*;G>#M-Bq%R3k9%(]fh(5;ss%nc,q.9+iv#tE&7/+Q;s%#a6V%W'gm&Tew<$F'F9%v1K^+5BV?%5w37/adcj'Wu[fLCJ[>#\"\n    \"L3b=$Xju3'8+VZ#6F<p%=r5$&;=7s$`:SfLh.SX'EgdD*CLI8%DF2v#PT10(9r(Z#O#3a*_i7T&-:79.F78U/XH8[#I<kX$c-Km&IdL0('<f&,#Qg[#JaUG)7Mc>#DO%w#VV*a*I-+A#\"\n    \".]1Z#OeO7eGa_,).`4E*L^Yn&OHUG)CFh_#t&2S&>D2Q&F'G/(Fh<T%]si#$<.%s$0=B?#:`1v#aLg+*ML`?#MglJ(QH0U%cIJm0V+nR]GCR<$@Fns$E_*t$='4v#)PSVS%2g3Bniio&\"\n    \"YDZ01F`s(6t,mt$d?[6BUQCB#*#JP'Ssb++mlm<.(;Rw-94Z?,G[Tc3*aNI3K/,G4/I<d*r3d%5<q%T.&.hF*(8Jt%rw,H3)_sj9sXU.=<9xt-<`c>#o#ss#Q:iv#Xsuj'1Y8L(HFeX-\"\n    \"iJT%6k^@L<trA_-x2/#,WjgQ&-7u2(@?hc)+BpG5eR&79-i-s$>R3p%A[3`#B6T6&,ZS#,a&YX$LvhZH/2nv$jg:g2IY-s.VH[(+3xU?#T`ae)S&:[0G78N'HW^Y$%7Wm/grW/<J@PS0\"\n    \"Pna1)bF5Z,8.@W$]4iv#=(mY#XnrV$G#WA+Hwe@#<oY>#48G>#/McY#'hsU.#)]h(j-x<$CnW5&S3OT%@+iv#<sQv$VoRfLR@lR*D_[<$w$@=-Lhnw#6=*p%`YQZ$E*Tm&^+,$,&E6n&\"\n    \">-,N'2r_v#`Hpq%9+VZ#7@N5&N#rc);u_V$f7Kb*H9G3'=n8m&c`%p&ZA.-)_Xn<$a:9'+KRI8%f^5N'Crh;$=w4j'b#$3'WQ#7&@[N5&Gh3X$dv(0(Mkn<$GohV$,DcY#)CZ?$FXiv#\"\n    \"TD%l'jI8r/6+`v#MdB>$w5:V%$ifM'sx1?#c&b39svTdOJPae5$].q;oXi_%lEw=-%7ro.dgo<$<hA2'Ns1O'0?>O0J=.s$Q-X=$e@PZ,0Mc>#(<_s-ROVv#M'4]#S>*I)NFIw#Lmv`*\"\n    \"<FNp%Ab[w#9(iV$e4ffL_lo2)jO'm$o8%l'8](Z#&<rfq5CW5&7x$W$9XE9%9LSi'kcRV6TnJm&`tJm&q[F:&L'Xp%WSlY#2lL;$U3ng#/8o/1S))k'PSs&+W_3t$>k&Q&Nt*=$2iCv#\"\n    \"G'92'5IjP&Uk7@#YSn`*KDWE*X/u8274.w#w(9^+Y,2S&Q'/W$14vD#AZuY#I8*e)?F7W$COR8%[_Vv#DrC?#6VP>#EqMe-9^AqD(e(E*J[60)Bh@@#k^%K#DtNX$c3s?#D?'>$hDq2'\"\n    \"Lna5&ah/6&BZ6)*u7Al'[0O=$5lu>#6?8],b..01X-B6&lfU>$Wg]2)(ehk1UD6O0J_M;$v$v$,pgLK(s?*m/Ibp?5gb&60A_1n'R;2=.hfO;7C5>$6Q9XB,uaE>-ZMeN1CFsa4qZ5r%\"\n    \"]aGn&[tQ>#rCJX%X;;S&?_82'bHEY-o`dW.OSUfD@CSB-G5Ow$ePCB#]Cc_+?bD@,MdC,)FOws$qYNe)8L39%K9G/(=(%<$>:7w#rnmW_*g^[#aOUW-?QqG)[#N,@tV6V%x)0s$Gn8m&\"\n    \"YSeH)Hv--)D=iv#_b&2NIn7p.50S=-B*Qu%g/5^,Y/%e2aT3L#UeX=%3SC;$Mw<x#/l-s$Sh3X$T996&47wS%xLti(9CE5&Bk&Q&QGj&+Kqap%GaZD*g-o[#K53&+dS24'G:I<$k/.1(\"\n    \";.VZ#M<b9%k`a&+PHkt$]pC,)x[OQ'OX/Q&<I[<$W&@-)Fke<$H$4X$?$lf(:M1v#KFMZ#/]_V$#gdI2B*lf(C<0Y$h]R-)x^(?%Lo_;$U6n0#%(5b@E(ex#Z)dj'J<Pj'^V3E*IZ>r%\"\n    \"`a,7&;(7W$:UW5&0Vc>#STG3'O/n`*:FW5&RD71(`)Hj'4#%;%2]c>#]i%p&@nVs@?aFF+Z1r;$<xL;$#Y15/>Or?#vK(hLJb(u$>e&6&;UWT%FlY>#LqwZTo9=x#5LjP&4aTb%ui1v#\"\n    \"9FIw#Uwiv#Q/WA+;x1Z#?]Cv#n<IT.qUFe)%PEo&%$%-))wA;.I$9q%Oq7[#Y606&;wAa%1.e8%76Ud2[t`:&htMm/GWfu-jp(k'T5`0(s?_hL?6Y5&]d0#$TS$[-,AP>#<[W5&I*9Q&\"\n    \"9RMA$;%%s$>u:Z#9=e8%'0q>$K_ww#I_E9%ce<h>>=ZG*_EeS%$ThV%=BY>#&(9v77YeX$sK<?#poe)*uY#@-@VUR;')`+4Wj]x6P=et7QBf5/5&-K1GmAa+oiY++NGW[$u);S&rKSj0\"\n    \"$p@1(%;wM1awXf2kTeK)O>a[$T>Qo/2J(52v#g<$ruMs%OjdD*Q8^87)6]##6INP&L#%)*I;[L(#edu%]Zxo%v*(f)obQP/1QCW-$5V#$CVV*.7:-;uYSl>#`f57g^@WReN/L#NH2>98\"\n    \"&46L,VITa#USW5$NI2X7@$5,mweOIulr22%M66a3=898.8u$;H,IZuPaZS7/wWdd3Cd#A#GR7lLZVxb4Hn<W-N2o%%FVkJM%&>c4w?lD#]A-+YBf?<.=@r8.VxZg)Y;.)*6>#s-hfV$>\"\n    \"-<Z;%oIvm'rACD3N]chM6^;Q0k^x@#cM#J*`4o+M1#n=7A3YD#Y<'u$IrjX%e?:8.K8X9/:FjP&Rxw_#kV;B4xox>,EBUG)@rn21?[aP&R/M0(+G(v#T^^U%T;2iK<?Hp#dlcY#8R3t$\"\n    \"QE+]#2OcS%:_&6&4._'+,,l,3Zr)v[Tuai(^W&2(Kt7g)VO]PuP2PS#nIVp%>]oP'.>X[?p4]$5c)+5]p.V9/dcCZ#>jbxkAUSY.IS(v#vCLW-do,Bt$=wG*YUv>#-TC;$ZK4]#,5G>#\"\n    \"30J`j[WKU%:MgHQB0qi'8cCuGiISL(>7%[#HJ;/(N:Vv#Jnnw#%b&.3fl<E*m-nK#Hn=Y#2dWjL'grD34wTP:OeB+rC^N,]<mmK%>HPo9Cdg9;t>>p%f8Ev/F/###3&>uut#/p$bGSt#\"\n    \"1&<`#ZOPb#+b@d#N#:f#%fsh#Q3)k#$W4m#FJ?D*-K?C#FN(KE)i,G4r9PQ-qSID*x1fL(dWt9%?1[s$Shc12)n?g)H3K01[P[]4-@XA#9'ed3i6+;.BP,G4dn]A,1rHH3fBSP/9R7lL\"\n    \"^%YI)`uSF**[R1MNP^Y@JHl)4M2'J3>:cS0jA%&4w4NT/6I@1M/L]s$`&YA#pltKMrRcGMawsnL$HF/M[N,J*--.[B8$4mLjNa.303Y,2lqU?^`G>)4BOw`4rDJn34]K+*r]G1MQZH.N\"\n    \"M17:M5,'_-c^*@9)@fg)YiWI)T:q0,PZRv$fX7hGd;Qw92uPkO9p=nE9tVNtE(XD#'>)mLhN4Z-wvkT`;;Rv$%$;v-N3mA#bws^-^0V'8)E&gLJ,,G4(L]s$o90u.,N$=.OHOA#g#Jn3\"\n    \"XaV_&m,wD*[2.`GRMW=(ThtD#sn-L5^p<j1<7Il)%cn$$;F#7<`]qv-B`tq2?U%],O-p:/nNf;-x+87MD/x.M1:Uv-ghZwHDW5t$oI<%$[R7V8%XUS7Fll,;4+8I(6m_6&4.R8%F4RBt\"\n    \"+rPR$D2pF4pe'3(EOwS%FScv,c5BD5nVC^#(V]9&I9u%$dFbM(,u0b*7jGW.+=(E4$Iwv&porO'7+Ha3m#q6&:W_D3d+wo%A_(J)CRVZ#4UO@$oi;O',o8m&XVg`5,U:N(Y3+]#6q.A,\"\n    \"kZN>-j7l^%;%@21<,$<.$/%?$>D]H)tI+6'Wd14'/7Tk1;c'b*U<gM'#Hc9%N+vY#hMvN'(^;k'LPG>#T@M;$[6J&,J^p;.h2rT9eoR1(+<?E3Ykjp%V`$#%JdK&&-shQ&-fbi(3qw',\"\n    \")eqBs4PcY#wPDY$1iga>x_T58xFDv#OHas*kLlXu2r*H;xM1v#-t4@l:AG>#MET6&E@VZ#om>r%=:rZuqiN9%K996&0BDa*K9gm&[gl0(Nh%@#Vu>V%E:DZuIBg9;)C9Q&va*.'LUV?#\"\n    \"(aoT$3+[8%fCofLECR>u2X[s$WBl/(5XXM$Icc>#<=`?uA<YgL@7RAkek.T%&lh,),?pm&RN-)*#reU/82Yu#5r-d+2uUZ#SLZ5//[aQ/$*=Q<h#p30jGP>#YXGL2@9PN'W.GZ,tO0'+\"\n    \"nAVY5-mtV-v9'q%e`w-)%6^],6p9Z-Zl32(f'`,DpOQ>#)m5E4)5/h(d>`0(d2ZR&s@>(5hoqV$/q``+/_q7'8IK41MuB#,r4x]kx%oP'eb$dDVnX)^'--N'4Hr0(,=D<-8S/p&31h'+\"\n    \"5&C8.F)Guu2CegDm_#c*Wm:0(4YlZ,x<+g1EFAW.CW1k'n*S[#j%te)S4vY#0.MB+Lg'v-3pek;&.`<-`g=1:o,Tv-AM4%$[rEI)5bCn'v1A?5skb@$AS4**/;iL1JjlR&.R][#'?*@t\"\n    \"4LsP&?+ha>wFKZ$=[3t$qOeG]kLlXuGoaT%0G(v#oVtq$A+lfC>L39%[]/B+E-p2'NgUg(2'Bp%InnW$`=1<-F'tT%Tm(k'Xv10()K?T.2;>N'PN,n&i;dJ(=:R8%Fqx-%B4i?#Mbe8%\"\n    \"?RET%4Y1v#x1C&6RN>3'SKBU%l<xP&IL@<$A`1Z#T,qu$3*FH;IoWm/U#@H)SV/B+Mlc##$Wo9vS?'Y$-=r$#8oA*#UY$0#[&/5#Ztgo.9BD]$-/q.*8#;9/3v+G4#jfY,1#BCO6Bgf1\"\n    \"Q6Z87'4dM9bR?S't1or6dc.)*;.%<$EX75/35-J*N;OjLx=xD*COCa45qKB#Nl+t.MV&E#[UHp.c8Qv60[TfLix;9/p%]5A4Z:E4UdgM'#cmHH<T-i1'C[x6<xX(.AChhLe.gfL80Zj#\"\n    \"/'m_'8A[N'eOwx/g<GvN+j^i)D-,3'w::/D2f)21kBO[1bAu?#Rrlm'<nVI=0H$+<UV+W%m8hU%u&gJ12bX=$f/6n&R*Wa5?p4]O.TJ>#OE2sB:Qw)*t]gA,5ISiTRKW62[K_(*t]$8(\"\n    \":ZMD*.9hs.9)&ouZW(q0Ox6c.O5=?)g^1k1k.FX?RX<v#=]ZE$fLja*q]F6BT2tZ%a)A8'ds:b,OrdF<?@n,4%pE*AK@aBOXH'f89Q`>$tobXrcnxb&LclY#dC>(+M1]n&G]sS&doQd)\"\n    \"U3K2't[+2(VhSN0vt)?#^WX0=Nr[[-t?oJ1hj.51PYNS&2K,@7obR<$j`O?6?s^S/?G;U8kkRs.6Yu>#gF9f)1eD@,)5AT&<(f.2UN_G)X-':%3l&c3fwl,**BG]u9)hB7'n96&/5[M1\"\n    \"%MSY8nh.W$w>-e2#9]cGKZ=O<-BRc,Gn$T:[`[/;Ew3?@<KT'%hiS^+vBvZ,`kRs$%11p&$,>>#WRp@On?fA=?Jd$'%NId)g=4gLS?o8%)7-_#K^<c4M;^+4iI==(-;:8.KHuD#6.gm0\"\n    \"3v3jLLqugLG?Bj0>x;9/T:2=-x.n=.@I.[#fYYD4l7Qn*#((02Mt587kiE.3a^D.3.r-*N@3Q#%T4&F.s^^D#HEBF(Nj@/34WG>>>6+^,O^^A01]_V$Y:5c*AGb*3_Y>X7uAG>#2:WP&\"\n    \"huSB+%ta>-'64:.WrPZ%d+l]H4Wn&4Q:?o1E396&#96j'XIL<-(8/5'N0FT%C,KPB&f$k(:st?63K7C>as7UJl]IY:@lu>@VC8:/^J]t/xIJ60m8g@#9vJU'=Pa4:RlLZ#GB)2UAl8xk\"\n    \"5e]I*<%`Z#3PlY#FJVp5cNbc2?xHJ#4lf)<L,^],Yi1v#DdU0(%um*5e%'J)[H#N'L2W,)DK:g(gQOt$KU.W$b8V0(RV'N23'S&,rWAR/(?+G4&o5mU@/+U0?<u=$>6LG)kUJfLWt?##\"\n    \",wpf%5iH(#Mqn%#F,>>#>::E3)$fF44c?X-b1tM(rW4A#^u98.=1h)3t=Ir8uH:gs?AovAl6;cu^PipuPRhLhir$S#Ae5rm;obUAhW1+9,ZSB$Yc4gt:cF4MpjD7[iD`Iq5dl:?2bu)M\"\n    \"e%=,#$&P:v-*8p$9$-;#>ugo.Km:9/[K*dMtBRP/SUT;.p--W?^kB#$45DT.PCI8%ho[^$MC[x6IQ:a#r9JG;59Gb%hD]eM/R)*4QhOh#M(pQ_Y$wLMIs0[/*1O[$wS))3mKY^,.^A.*\"\n    \"Lh>b@9=,F%sbfrg'wsnLn9::@V3Z;%_E;s?r[,g)ogegL]+.e-P=hk+jnr?#:xNh#&j[)4hm@d#e6@29T_1Z%H-:X%iX0$5RNgU%INpm;^di'+0$OM0viEO'IB9U%c*AW$Z-=X$+M8h(\"\n    \"i/6?$Nm_g(^1B^+fvcN'/i$s$e`T&X^=>C+;=[s$DwUp7Um$$$>cuY#;pfDE4N?$$,VL;$D3wU7pNJ=-AL`Z#U)@)*'>E@$Mg?d)e2N&+ZtIW$HKR'50K=h)j`vj'_nIu0Z_Ts'`[g41\"\n    \"Tjp6&RZtX$]_qhCl289&lY-+<8pp[#XlJ@%j`=a*=FR<$Jne<$4@lE*@jR21p9O5&W=Cw,C)VUdFLDv#K3F]#CFi;$^Z$d)[A7],)cR;%S6lJ(8q#[H6Z2p&micY#lHMu$R7qS.$n;)+\"\n    \"PW1k'DWgV.fC9/)P%@#Q>G.?$1OfJ1ipJ,;aho4(3DP>#S.w40(MG$,^-,j'[n[9(Gff8/;FIW$owo]$(cxB=CEYN'`lAr0JkUQ;dR5j9VaY3'8/Y',>Qo9&(VWW%62Z40Gq;[,+i>G*\"\n    \"Z#-Z$aBqU@^lsLC`D+>&&IoW$:uhV$CmN)>vYUQ&AI*T%?(2v#9x<[$e4#E*O^^u$CElj'`+8t%.rO**>la[$Y*TQ&U)6?$P-0:%g?jM0gb)6/`c.T&,>>>#tKN`<t6vo[Zn$##$N,Ze\"\n    \"LCNT/b]jj1'c7C#RQNjLL@<9/<Vo=%H0^M'bCSfL[s^M'9Fn8%&]bA#H'2C&]'Gj'3_7:.Ps$d)KDhJ)+_=03ZKJw#QM(4+)9Gb%02^N2+9Bj0EcXjL:W@C#,,=^#u7kGkH+NT/9=E.N\"\n    \"Gn$&4f0H_&@m:9/9jGD/R]jj1.U^fLb#TfL<hhAOrESb-7nfBJ?om=7rO>c4QJ,c401b20QG,c4Kq'E#OJSq)r*H87HZ7JM^bP-Mri=c4B.FN0LA#c4&^B.*#<8.Mp.*j$(*YA#sQj-$\"\n    \",o$],gU'f)7Gp;-6PP8.rYRD*MYHg)3OqhL8fG<-bO`X-Fa9[0*x6x,<Ek7/.u#s6?<qfLrX_TM)(^fLS>fn$k7o]44wgBJJn9@Khn^b%hS))33Y7%-4WqE@TP_nN*KjGMBhID*I[nLM\"\n    \"HABoL]qR:.9mLT/EC,<.E9Gj'nG.a*LQIgLcGdw*gx)9.YPjc)HS<T%4Co8%10,;Ja0j(.TAP>#2+@W$;..s$:(`Z#7oq;$6l(?#4(r;$9[/m&84I8%7:*T%7cY>#,pia-ii_$'gR<9%\"\n    \"1VlY#BkET%7+7<$m&7617ic>#+MuY#3`uY#/`Pl2ECes$:FjP&:o?8%?U3T%md-[B'1Ft$G'96&Hnw8%1f1Z#?3P/(AN:K(`M'9&=C@8%0e+I-M;P>#;Uw<$MYF_#5rH8%<1DZ#BFwS%\"\n    \"Th_;%gvjp&1cL;$];9G.2.[8%tZZ^#<7[s$ND;21'P*n0MDYj'8I*9%N@BK/;+M?#[:OcMJ[)Z##qm>$]]>D/3CaP&cXXgLn:av#6icY#<fu>#<@vW%HRwW$AIes$^CSg5:%.<$Eq]M'\"\n    \"I<,j'>O3p%>uhv#-VL;$`ROgLDaSr/-V1v#/GP>#1.QXMZP+T%4oLZ#:chq&Ra^u$IH5n&8.Is$7le34k'b<Ul*X9%Be<t$<:'L5^T=T%5r_V$Nd1k'?=ns$=o(v#5USM'-i-s$4r_v#\"\n    \"CL.<$sN3t_l6Yj'@u:?#H-Tm&D?5N'*)OV0DUN5&Mw]m&`[XgL)X8[#;+%w#ib$mL5Y6G$EkH(+3gDr8d5&Q:>[Ep%6Cgg2P'_j:YR_J)$wt=$/(wo%.s$n&d0fS%N8nB$@L'80LcC%6\"\n    \"<7@s$GljMECP4&+g^mE3#RTRC,GsV$=0Y/(Za0Y$Z;e)*EqjP&Ckjp%/xZS%@XjP&V#vJ(FxSj0Pj>7&T[&m&J?XX$_)%L(Y^t9%FF<p%h&vN'A@;Z#/GY>#@qn@#,DlY#$Y$Q'-V,52\"\n    \"9q4j';=Rs$6LET%0lhV$sO9^#@dB8/5uU;$Y4ofL7j6j'Ep?H)9@@w#Nj)&+8R*X$V^uN')=-L,,;$p.X#m3'CI%W$m=kM(*tChL1%_2't*1hL>G/w#:(.s$G6.Z$C(QI7Uq&Q&BF_GD\"\n    \"$=7I)a'T6&ZT>/(S)2O'TtnS%3Gc>#v_B^#^:ffLZ>/<$97.[#<.j,*ht'hL%;&w#@58nNUYc>#717<$+E9hY:F2x$7@*p%9=nS%?(.<$/i-s$NAUw-X7+gLt)^fLJO+T%N#<&+4sXp&\"\n    \"vbO,M(W)<-:H*T'qnGc*EX<T%#N?*MkI>p%j18P'nLkM(?.nS%R^0u$[d_K(<E/E+R);0(rGR^$3u>%$>[/m&HETq%84r?#0f$s$`>eKYLJlY#J)/C&V%VZ#&T.>/9Yc>#rekgL2miV$\"\n    \"%r+kkkE[>#Elxh(5VMZ#k<.X-0fL;$cmCs$)s6$$m$Z$,&V$A6RG0J)-sjW@6?RH)WH0Y$J2n)*DFnxkYUsH?E3>X$&&###%&>uu&[Vo$Qld(#e@$)*SL1@%dHWl(inL+*7:'E#-NYx6\"\n    \"IS'i)M@i?#@Cr?#FnPb%Rr$<$k2Pb%n5>W-'W>_/T,P)4TU3F5Y<j?#*$Vk$7n3iM?%<9/KW[$9_K2T/<n3iMv'8s$2<Wb$iOK.3q,Cu$5<XE*rqQ2m$vA^+hv(-SHV?],XC8q/UDnR&\"\n    \"YSn1(a+(rZf?-u,S%ff*VmJ.*3Z;W$thdf:4<0q3+IeY#nr<87+lXt(Y)[/VH7fJ*8vqU%d7<`u>=Ad=r&2O't3?K)1DcY#mX:&V0YXo&#@+Q&.1X#+Qsno',a.u6U]&V#KlsL(RS8B+\"\n    \">(T].7u/5'^sTqBtlOs%H)Le;_&0uu@.6x$brVM)BO2COi#[S%=C^G6m'&Z?5Y(Z##@:J)(v&'+dgRJ=921fFD)#RE]QEv@P,f'.inFa=u=$9.6Tp1Rc(4%,>N+&#.iLvu1:ns$?C5##\"\n    \"gJ>F#+p`s#YBic#F3)k#SIuu#8PUV$Jd=L#UD.&4Y>Y)48J.aFaWN/2W]b>&pwEe-']_6(a2E.3bMul9L1YD4@&dG*+GpGMASu)%c9Gj'fPH.%QV-g)H9k0,JbuS/YD]'.*r+gLh9j?#\"\n    \"9v_T.xD-_#k8on$Qf_8.Dh_F*5<2?>8[uS/&E.^$iq'02@+[hYG8#'$tBr8._MPd3?]d8/e^nI-IlP<-o3IE.[ujI)R8rnE]*UfL61B.*u8Zf;;`E-Z(rn*dl4;&0,O%],oT7x,bkNB-\"\n    \">s<_$ua)*4VQ>wTckf['h($dN^I$iMjG5gL3A8+OoUPf*<was-E&G)O;UOk%g?XA#7g*gLTqJ)8aZ?-d@mLT/,R,O4%J`R1G+F+3]fK$p;t2ns`4`BSfUCa>_/E.3X/L6a&'4<o0qugL\"\n    \",)]iL;O5hLO2,1:S>LkF,DSfL=SQs.4PP/2&nM#&d`DD3VuQ,*#.SY-A^CUqm2Te>;i1T/S_S;8PO:a4CORLMT&1f)+14N0@Cr?#/P,G45c.3:XO,<.g<'u$VaOZ-G=tEed,4j1#IsM-\"\n    \"NC#[.V4@]6n*6&%ZS[]4,Q1u7<7-SD/w(hL1RKh;..pAZ*gi&.x2shLv6bF3&VI)cG[:H-GBMiL`4YG-v#lU%h?>)2CSRV%/DlY#@PY>#EvH-)0ASn&w#_6&M4?5/n-K6&@B2R',sro0\"\n    \"%+Wv#5vR)$>RlH34C2b*8%J>K_IT/)NIbp/%c;v#*7,uBR/;E+l1f1(=fC;$#CAN0Cs2&+Qk'&$$FV)+65CC,E[[w#lGh-2/ot**,_7(+x@6hGU$A8%US(Z#Wk[S%dth%,Ymf=-H,[H)\"\n    \"wjR*+DhwB,K0#3'L;Hc%PU2)+tBac+wJQn&:uU;$TMe-)RVW&+MC860?McY#lO:x$E/jA+bUC[,Q=$H=b)(e;li<X(0]@D,K'VOB#TuY#eX+`@?S&D,r(]fLP_9303'/,*?xE317=PgL\"\n    \"f)cM*9A7q/[.SfL(Jo9&OsU,)J`Y$,;`lY#]1OM(1xFM(ZNc%$6;P>#@w86&gG'w6N$,<%8+`;$7[_B#[;h>$OqjT%a]x]%rNlN'?e8Q&iJ6r%[PWq0eurB#:h,12UE1#$.[?G*j:8T)\"\n    \"=@6:7*CoJ1H.TP'W(1hPw]Am8`g>N'Tnwo%8ccY#Y#dR&5;G>#Onn8%g1'F**$FY-%7L%O]k[S%A-53':_oi'jZFg1mmg6&R0F5&5Sc>#A[N9%7Y1v#X8q[us=R-)c0Hu/Qt;R51la+3\"\n    \"I8l%,BPeS@JjP>#8%MZ#B5<s%`X6w^fMcY#f%n$$;MuY#OjCa#J&.L(&4=SnAfBp7]Du>%?@%[#-AP>#T=C8KBB:,)_X*X$;(b8&T($#-nVXjL=CJ<$V(Ik(A5ag(ha4,2R6P/(7CDx$\"\n    \"GFws$Jt3=$Hm14'`n`20sX=gLoWxr1Dp?-)%=.Z#Hhew#UrRfLZ*(V%HaC;$*J(v#b]Yf*sxEC$5uUZ#50G[CM$xW$E/jA+<>mZ#T]:Z#E<9:%0ix=%3FjP&0gLm&SOeS%,DcY#2i1?#\"\n    \"0`(Z#;*cJ(.(bk'>F3T%g8m3'<3Yj'Rh_[,8F+]#i)Z]4WlPE*EpQ)*9#/'.#ubgLL$7v$7YT:/$16qT-X6:<;5?^Cb$*m/2.pfL6#iP0?-9:%CS1v#.DG>#OZpU%D0D+*o_Bf)OkWP&\"\n    \"u4BPNINff<,knE$.l$W$BgQ)*a_:@,xQWq.sv57&Yt%_Sqk8Q&CwWX$@kmP&hAGA#KdHD*T*4t$0]1O1$c=%5xN?%5)JI?#U-i&2hPe-)WWG3'ER<T%`4SfLYajV$5rCv#C%#KSpqAk9\"\n    \"o/Id)VB`f)BNqG)W80T&T6n0#4)V)3HpC4'4P'976he#@'a%H)wBZ?qX>,M(X*8W$Ow/6&qfj+*`/7uLEBxd#K$F=$H4rV$PQ>3'LQ:g(HL*T%,YL;$Y%V?#uRZn(5hq`-UGUr.XJl`<\"\n    \"^q9#?w/HY'fI7[#a<&n/?`:Z#0u$<$0O(3(w2Kr.H50u%BX,3'Qe[S%]EJ&@g:;?#]UiS%viJmAfSe)*.g?=$JW57&4bhN(-]>I-A0';.VO3t$>l$W$q-V[,Lqns$%<[t.KGf1(FeE9%\"\n    \"2-3P]X+]fLm%[>#.SlY#B-0q%hOC<-a=]fLqrYF#[P.1(xmmS'Q?Xp%8<rr6;<eX$91nE5xkGU&Lfb;-.PC;$pJ2#55-0(%wn5K)i?Vi2gL7[#V)GL:mF7[#n+bS7$g_;$uaX,2vSZHd\"\n    \"aU&m&MTgQ&.Mc>#)[7T&-3%iLV;Th(57eS%ek,AOCC9K25<***DEe*$LMG>#VsP7&$jF&$c&_e;K>fH)GMF&+6M*+3=h6S[HHpm&?]C;$^%6^$4@WP&c8(SIN/7L(WnH(++;*0(/RG2(\"\n    \"q^BY$^G<qMi##98+FDJ)/?[9Mb2ZJ(eHW%&*xtm'YZkd;>gl%)lG(m&^e-X-58YEENJpB+U-eTiN@H>#OJ*I)QTa%,UgjD+Li;=.>ltI#QU7w#<In8%C6>N'Ij1t-9AbZKsJW[$W:[8%\"\n    \"hk$],af`O'5pCv>$Qsv6RjDE4_S2v>HZLa4%[*G4Ub<30S`jj1d^Tu.b?+C/GnHh,joXjLIQrhLrGPA#&-UW.%iH>#YjO?-up>`-ZFFX(cV))3G.cU%/BiAJouWe@-mNT@0?oI)#wo7(\"\n    \".=Zg)s]v_,=46q7ZWiW/J%.s$``G>#2CBa#*V%)@[JuY#XJBP<pxL?#,U>UOY02O'x*4TLtpBT(J[ET%U.;$-0:0kMQU]wY%Bie)W+>$,/mxC++x<G<*><MKdpc/C:*o>S'h/C5L$$Q)\"\n    \"89<v6#<=`>hQO1:b]iF?ceRW$XYqZ-,Ger%7l:v#ZN4:K9F7@#HJxu,N?533AMvk1<mx],Hm?@7-J_s-Q@`;$8UUR'fb:%,d*85<BZ679GJP?,e-ZZ%H_n62?;R3'u;[Cs;@VZ#lo>8%\"\n    \"_kHP/U>#)<oY(9/3/q.*W_Is$;lm=7?L&@'B*tq.5fjj1e73v6Q<g8.9.i?#L'b)>]_FO1&TGg1UpVa4x?7f3>DRKs&kn5/Y;i`3TSUR'4xUv#hk,K)N00u$pW;E4+X9[6hPIl1-RPQ'\"\n    \"8=Ps6kbhlLokkj1OoK1&X@[s$^K]*7lmAW-ILpE@ed`m1hueD*Lp%32TUa=.E1NM-9DNY.DfWF3Z6h%1R<OA#H)0J3xr%&4Xfh0,#QId)Zo(W-reSNipbZx6=3q+MaN.fMoo598pT7W?\"\n    \"'3Zv$iS9/)uwMxF=McY#ma`L)aQH`*kb^b*^g1k'xV_H25=Tx$cTx4&U]'g)^D]^5Y028&_0J/1=X0YBQTTQ&2f(Z#]MW&+>@k@$onXgLGYC;$mU8u(uN+m&)OYV)CL82'7S(v#L`x>,\"\n    \"<>cY#<Ows$Qwws$.]C;$q)F^,Mdds%V;1r&d1`F?b?hM'R<$9ro7mk'^FV:8T`l^8o<vO'I-^Q&%?$V/U%,dYe='COJbTfuj`=,?LP<IF%ftu$ehp'HnSF2(]Aoqhbx]P'AuZS%D._t6\"\n    \"Kk@W$OEkq.<JW4''S4gL+RB#&Y==N1E/W&+qZ35(NqEX$*T3&+O@W2'NRgg2/DMM:M)Mo&Lxa0(d_Us-o&,q.)AO31NQf>#ND[K5+m*s%x)Wl(R+5C+M`VM0Ye3bcr,d31crwlDB<Nl%\"\n    \"RtGA4sN8W$<8GT7Jj>]#Y+MO3'QF@,ASvmS`*>o07r1$@jN:a#AlU;$TdIYPFFvg)NfZ),0,mA#GB#n&T#oB5PL%;%xi7P'P,K]$$+J[u3+vA#S/ic);W07/7rR>#^IF,M5)Sd#3%Is$\"\n    \"$5jb3Lhw.4E3D^+R_'^>P5mj3iG=a5O]>',EPx6:p7=<%+oJl'Rc4Z,Cfw3'WMp88904v:F9HO0<[:+dm?U]A2pQx#[UEk:_/SHF=4ZV@oWLJH:VC_%S1'Q&6&#B?jcxi(.?=V7koj&+\"\n    \"VYH981l:?#(Q=4L$$8^5XCIA#xwNmJlYdn&Ip_0(L*3p1_I]*Fkd7^5SDj#?m7.X$I3Er7Cl]605S3N1wRB_4cqj5&]kI$7%7;R1wX15/)&>uuTtUxLjTw##^d0'#6&*)#-->>#+dfF4\"\n    \"^IcI)7%W(&k1TV6#@n=7@oq_,V5MG)9*([KvW#C/ojHD*p;Tv--LBu.gag20?.xf1Mt587D<Mb7a2Bb.K39Z-]&PA#3%#>Y4Fqf)w;PA#f]w20iCV5&Rk*9%rpJF%Z9j0G1;Ml<S3*,;\"\n    \"7XLw*_14`#$]id*J%8TIAj4]#boM2KnC28/[mMfqPp]a+j95?`]nNT%ni621<8gV-xxp*%k=E0$R3gM'9M1v#Q'K2'<]_V$faZrLUoj's+Q&KuR?9u.A*<%,Ol4i('&/>,v$?q&O:ri0\"\n    \"dpOh#?vlFVnWi0*<G:;$2Xx.(FYVSn-l68%KJ8>,)V_V$.U@p.eLBN(bMq>$M,Ih(,6pV.(x@[#@;@Z$$bsL#0Q&au&[_R#3i+uurb8T;&(^Ho&V@W#$6xH#lp8lO'.jH]J,NU#Y:-<p\"\n    \"$v+uu8`]U#]-PS[4.P]uGkq<.&>uu#?PiH*pwaon_*UiBuV)XL)>M#$*iBv5XAic)Whi?#E8JC4*%C(4BS7C#1m>x6llE.3:2aF3YZf<$BKc8/PD[w'NvMF3$/WO'cDQJ(u3YD#:mnD*\"\n    \":]5g)c.5^4n82,)w<@+4@f)T/xCXI)]L65/OM>c4gS#-3T4)v#7AFXCaNAd3NiSfLv?o8%]O)jp@G.$$Of3^*b5***NtI*5?IKQ&<i:KMYi6C/FejZ#hRQe4+I7,*M0=]#F:vj'+I-t9\"\n    \"IG;hL[lRV%t=g#,v_=X(&:4R9M`]1(lH3Y-1oa[.b;[rdNjjD(7eJ%-7aoD4ks7g&Q'G'GpW&j22$2jpF8JA>8%ED+^j+k&S6cBGo?[p0#FZrum[`99f_`v#j5%D*07rW-Uf[5'Dwk4o\"\n    \"XtRw#RD>59dl?+`@Rrv/#<1B#k@V*4@:*R2?h&@#caHR&iGOZ6dW,,2/WLBuI<AX-)ero.I2LZ-Ov,Z$'1A[uXbT3(O6o@#Amkm'h_?guVG4C&1G^J)5]ko71dPq%wnx+Ms[03(NrC$#\"\n    \"#>_7%siS=#$_,3#BZ)<#ho+Y#7.i?#_QtA#3_aL##JpeXN1CkLk][`*6ggW-JP7.OZ;_B#_^#V/KlR_#d4r?#O]jj1YPOZ6&In=77W&],YDic)_oJF*C]<+3e@;=-$VY8.abL+*sC$Q'\"\n    \"h[^JCL?DH*L@[s$dW.L,sGnA#xL,W-a`p?9*uLkL&I8[#A9<s%HCTv-*tUhLk:L+*/33E4cRg8/PoIMN2d,pLk@HH3hS0XLv@dP/Nghc)COTq))J+gLU_Za$BU%],<f)T//SF,M:9E.3\"\n    \"BLIP/4QeuL9GtR/@mTv-[f@C#l+#73=^YA#d9J@#xRn92<%p+Mjd`a4roo;%+U'[K-3H^,l1pb4E2q0,t]a>$j4`E4o=I%-N^D.3_;[6W=GOq2=D^+4pk0B@97ggL/Kco.Lq[s$ElVI.\"\n    \"-d%H)n$6T/gG+jL*gMO=8+dg)GqC.37i#OOiHuD#lCY-Z7BiA#R)]EnPWIv$njKDMv;.-&%KM8&Z>$L7pCn_s7*,R&aF#G*=.Rh*(Le>#_$fs$_0tl&g5[(>kKi4'xOK.=F4#`4>^uGi\"\n    \"5&)o0O<I`.aMP+53%2x$0#jH4I`Df+Y-a]FZlZ)EUTOeDt?JAaF<+'$13(L;50/Z#Sm(O'4mN%tpqYU7e=f8%7*^2BGE.<?4p@q/9vx=u]J-V%>;RR&j[iV$*Pgm&*6PM*buLq8knap%\"\n    \">$2.36V/mA:YG>#MwjUmA)`K(-6V0(GUET%g]W&+:rqV$r2lg1'UKD38[TD3bKbR$A+n]u.)EZ#3'HN;Y@%Z#g8wS%7huh2Dejp%#R,n&H+iV&H=k`ueqEK(,qe&,#th$%/rH8%/,5Yu\"\n    \"D)2cY.c_;$'$#N'fX8u.3vk3+TAG>#>qsT%nEf@#B`rh)h2-*3q$4T%@,vx#H0kT%t&1r%^G<T%DRv+sf#Mk'r4vN#McX5(`T-d)V?4?#R3^s$ZN(j;5.*p%SMV;$5o(Z#?#qP&IPpg#\"\n    \"mrv@[YCiY7p1d>#lw6x,'/'Q&/rEnu_<wt-$7V,)v$?@dYs@ju+$U(*s[,C+Vmsw,@Nn)*IFsl&;rL?#n>M>5ndEB+4w/a<%`=bF*j*.);e#/3Lv=V1Xw-f=xtd2=.?`m:Vx),>$38iF\"\n    \"?:B@8`vE(5&g9v#TWJR6uRBZ/`Hg8%fL#G*=20]tS0xN0Oi1v#<sNT%FB1W$D$``=#;du#;65n&6D9p7u_gf)WrE2(ogJn/bK2O'jtts%F$06&:=3v#SI+9%rdxo%?[R<$]Qfs$_))O'\"\n    \"OSNe)ZgY7&:_s5&<iIU/@9(Q&.&B<kLbcrHq^wv9VZG:ER.Ls-hR@W$u:Ek'AU(=6P-V=6=31,)F^n-)4wmc*1GcY#8]cY#g:M&=-6<5&2@jX$i-Pr/PAR8%S=Yv,MRI@#h)GjBx&U)3\"\n    \"u0+9%=/QA#?X[W$:+Vv#T=CW-+u[&*@LRW$seU>#l),:.g_jO:MwAs$`H's$J8D;$p?#ip>oNt$Kqo9%KBHV3k.A;%<_sP&Lu>dN4:Lga6t]6&;96<I95,##bH,T%1atonB5=;-pNel/\"\n    \"OR$##X,U:%XAqB#If@C#;)MB#ak4D#xx[]4A<3E4$M'+*UoXV-3Ml>#[_ww#avIiFooCG%68Bl8p^r#nCx$8%s=m=l^-(e9*H+8R41<>l)jJXu127DW@/NFr^BK(Wm<[SRRm_CjP9h_'\"\n    \"oIB,-f9BU[s2Xi&]XE5&M,_X$<iCk'j2?O'?0%;-s3K4A6/`ZuBqT^#XqX6#%)###X[TDN']s@Xm<L-Z7(8]et=[v$d-D%%Lc/kXgK(E#OeP8/^Ju`4[5#d3`lPR*X,[sg4XkD#N(_3B\"\n    \"imP,*?:ni0-8^F4nZ8x,p7Kf3vIMa4P[7x,6k%>-+tar$3q')3A@rT.@Cr?#xb(p$n_@K)iA@d)8XiX-c2Jh,@W_aE]5Qv$ZT_*@R6>h>+_#V/N--R</fk(NVxbF3:i2t.]FK/).X%&,\"\n    \"X],@$@aQ)*%oi*%6c%r%@pIv5$WpX-K)iO'WBuJ(6VG>#5:t70h&<&+d/Z3'Bjm`*HYr11S+vY#7&5B,BX&W$`)vx4watl2i04t$6;m925w879b[:&$?:2Z#]]H_#Zk;20B/j^4iRm>#\"\n    \"Dd_K(IAcY#L'Y_-4=<5&D?GN'ck;3,GYVY$x%Q]#hhcG*6lm#72NS],&QHR&H*g2'[;24'0/5>#1Yc>#.chV$fj[iLPlNv#*rgf)JoB8.&.MIGpDGP(:8G>#67E#7GV=**JP(Z%baa0G\"\n    \"YB:i:_.vY#RY8'+?IGMEq3F?#Lgv`*J;`B7;4:GDp#^g)9Fws$TZP/(hCj0E)6v]#QnW=.l;D&$T]7++D`O<6f%CD$Men<$QiCd4R]h@-`TWB/``*.)WAXjL/g'^#4vhv>bhPG*FiUv#\"\n    \"%#IM1Enjp%Adk',[Q>N'.5,##-w3Q'W9LcMP:$##$$I:NS@-##HP48NTF6##aN3;NUL?##.]9)NVRH##R3+0NWXQ##0I#5N,@,gLVO[3#+MC;$-,>>#4h.nMS@-##;kY5NaF6##WCL9N\"\n    \"UL?##Z*'<NVRH##EMP-NWXQ##t&C1N,@,gLD&,1#5B+.#S:F&#.mk.#.BnqL:ht)#N5)=-H)m<-Nlr=-7mls-3#krLsX5.#Bg(T.NH4.#Bfr=-C/;t-pm-qLwKM/#;N#<-m]W#.>F,5N\"\n    \"?0n+#;1SnL0NpnL+v:T.-9q'#[(m<-c3S>-d'LW.#-3)#K)B;-/>9C-4cpC-IA;=-]Lx>-DgG<-9N#<--JKC-]qefM.jkjL>F[L-vpTK-?6v5M@F.2.p;ajNV)m.#UF`.M6%T,MK^u5Q\"\n    \";X$lLei?lLN=UkL*/K-#DBg;-OoWB-,x26.ch%nLcBqS-$.b+.cY<rLx)8qL%Y5.#<U2E-AhDE-W4H2(J)@X(qb%;H3LTJDApW>HTcgER)=ELYUhBdF,Pr'#w5[qL.Y,.#(bqpLCA]qL\"\n    \"g3C'#f6%F-b@?PEbGsVC.BoUC2.vLF?eo*H'ditB%dOVC6*TMF*'FG-I6eW%/1(O;%ibN;)3Rh2H),FHr(622F1vdG:C+,HEu^kEEr'8Dk<oY-Y3p4=t8C5B7dKwB6616MowCrC*vIqC\"\n    \"_K'UDH-,<-@ERl1Op'$J`f#'IQIO9BHxWs1s[6fG+7<LF3wl`Fxagc.7=AEHcbCH-afLH-:%pN-B6<'1AC7FH<v1q1Qt&##-;O&#_mr'#0W7JCU'AVHF,w1B&aC['4:@bH&MJb%o<n58\"\n    \"eC9/Dc-l>-M[xS^q68;8xLY#@rGG&#pu#-3/WBJ14Gl-$Rm>G281.L2.amdFgkqdF-4%F-.oBo-6gN:MsXEA-Bd&F4:K*.3%tLb]T3nKP17auGQLH]FJj7kO[V+XC?NPwTV3H@-4gCSC\"\n    \"7;ZhFhXHL28-IL25+lEWG8$##T?*1#l[-0#B=3ZPx-gfL8;?>#1ZS<?*;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#eEbA#iQtA#\"\n    \"m^0B#qjBB#uvTB##-hB#'9$C#+E6C#/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#SiAE#WuSE#[+gE#`7#F#dC5F#hOGF#l[YF#phlF#tt(G#x*;G#&7MG#*C`G#.OrG#\"\n    \"2[.H#6h@H#:tRH#=wI-#wpM<#@/oH#D<+I#HH=I#LTOI#PabI#TmtI#X#1J#]/CJ#a;UJ#eGhJ#iS$K#m`6K#qlHK#uxZK##/nK#';*L#+G<L#/SNL#3`aL#7lsL#;x/M#?.BM#C:TM#\"\n    \"GFgM#KR#N#O_5N#SkGN#WwYN#[-mN#`9)O#dE;O#hQMO#l^`O#pjrO#tv.P#x,AP#&9SP#*EfP#.QxP#2^4Q#6jFQ#:vXQ#>,lQ#B8(R#FD:R#JPLR#N]_R#RiqR#Vu-S#Z+@S#_7RS#\"\n    \"cCeS#gOwS#k[3T#ohET#stWT#w*kT#%7'U#)C9U#-OKU#1[^U#5hpU#9t,V#=*?V#A6QV#EBdV#INvV#MZ2W#QgDW#UsVW#Y)jW#^5&X#bA8X#fMJX#jY]X#nfoX#rr+Y#v(>Y#%>lu#\"\n    \"(AcY#,MuY#0Y1Z#MW9^#6lLZ#:x_Z#>.rZ#B:.[#FF@[#JRR[#N_e[#Rkw[#Vw3]#Z-F]#_9X]#cEk]#gQ'^#k^9^#ojK^#sv^^#w,q^#%9-_#)E?_#-QQ_#1^d_#5jv_#9v2`#=,E`#\"\n    \"A8W`#EDj`#IP&a#M]8a#QiJa#Uu]a#Y+pa#^7,b#bC>b#fOPb#j[cb#nhub#rt1c#I)'q#x0Mc#&=`c#*Irc#.U.d#2b@d#6nRd#:$fd#>0xd#B<4e#FHFe#JTXe#Nake#Rm'f#V#:f#\"\n    \"Z/Lf#_;_f#cGqf#gS-g#k`?g#olQg#sxdg#w.wg#%;3h#)GEh#-SWh#1`jh#5l&i#9x8i#=.Ki#A:^i#EFpi#IR,j#M_>j#QkPj#Uwcj#Y-vj#^92k#bEDk#fQVk#j^ik#nj%l#rv7l#\"\n    \"v,Jl#$9]l#(Eol#Zl/i#.W4m#2dFm#6pXm#:&lm#>2(n#B>:n#FJLn#JV_n#Ncqn#Ro-o#V%@o#Z1Ro#ulj1#g;eo#cIwo#gU3p#kbEp#onWp#s$kp#w0'q#%=9q#)IKq#-U^q#1bpq#\"\n    \"5n,r#9$?r#=0Qr#A<dr#EHvr#IT2s#MaDs#QmVs#U#js#Y/&t#^;8t#bGJt#fS]t#j`ot#nl+u#rx=u#v.Pu#$;cu#)Juu#,S1v#0`Cv#4lUv#8xhv#<.%w#@:7w#DFIw#HR[w#L_nw#\"\n    \"Pk*x#Tw<x#X-Ox#]9bx#aEtx#b64&#=+^.$i^B#$mjT#$qvg#$u,$$$#96$$'EH$$+QZ$$/^m$$3j)%$7v;%$;,N%$?8a%$CDs%$GP/&$K]A&$OiS&$Suf&$W+#'$[75'$`CG'$dOY'$\"\n    \"h[l'$lh(($pt:($t*M($*phv#$=i($(I%)$,U7)$0bI)$4n[)$8$o)$<0+*$@<=*$DHO*$HTb*$Lat*$Pm0+$T#C+$X/U+$];h+$aG$,$eS6,$i`H,$mlZ,$qxm,$u.*-$#;<-$'GN-$\"\n    \"+Sa-$/`s-$3l/.$7xA.$;.T.$?:g.$CF#/$GR5/$K_G/$OkY/$Swl/$W-)0$[9;0$`EM0$dQ`0$h^r0$lj.1$pv@1$t,S1$x8f1$&Ex1$*Q42$.^F2$2jX2$6vk2$:,(3$>8:3$BDL3$\"\n    \"FP_3$J]q3$Ni-4$Ru?4$V+R4$Z7e4$_Cw4$cO35$g[E5$khW5$otj5$pe*9#@/06$#=B6$'IT6$+Ug6$/b#7$3n57$7$H7$;0Z7$?<m7$CH)8$GT;8$KaM8$Om`8$S#s8$W//9$[;A9$\"\n    \"`GS9$dSf9$h`x9$ll4:$pxF:$t.Y:$x:l:$&G(;$+V:;$.`L;$2l_;$6xq;$:..<$>:@<$BFR<$FRe<$J_w<$cqGkEqcqc$8GhoDf(LVCn)fQDxmE(I*SV.G*xIc$Elw6/.U9GH+BJ,M\"\n    \"Qs5bFvwOVCjMBnD$co;H1PK=Be$Je#5*S,M:;p*Hi5bQD]W'c$)0oUCuvcq;RvElEI/(*NvUr)F9C4,H.HkCIB#8bFj7AvGoa`=BfougF#RbfG85MU1o:MhF)h.gLRC3'/jquhF2$w9)\"\n    \":2j=Bd.)hFM?%rLv/w3BDOkCI:%VeGDlDb.a<?R*K[5;):VUc$xVpgF0lDlE[Bu[01xBVC$dCEHix@qC,dKSDwfA']BqhjE07NtCuh>kE#0SgLjPE-G$HxUC1LxiFJZ.rLs7GqC4l><-\"\n    \"V.%I->*tj0+Da>Gxve:CSKD<B+.h#$e0=F$B#b#Hi*;iFtw8I$DicdGw3=fGvc?)%fmnUCbQxfCMpnrLH-H:Ci4A>Bhp,[&?CkGH2v<nDruVA&OYp;I#gTSDGZBS/=Q;eEp+8#'<RXmB\"\n    \"&jXVC2*%%'h2_t16&`_&H64,H6fN$JEi3j..NOGHT'1w-/DR7M'`rsHqJ5hFwB3B/joitBW#]rL?lB#Go&+nDiAS=B;t?qV%;-)%^7@[9?.krL,>%eMZZL$HDq16MID2wGIS1aNw<cQD\"\n    \"5NjkN6bU2BDOkCI6q9GH3R+RBv_ECIiMm<'(o<GH6UvV%Mja@$0Pw#Jp6`aHt(/vG)W6D%Dpw7MWwCHMjXGHM%YI6/^fRUC4dfgLKZufG<k,X$9;7%':D+7D&fs#Ge2'&87xRp&G&K1O\"\n    \"0TnoDBmO4+$-GN2$DZ?G;%=GH87gkMv2]dDC^W4NSbZjBA:x+HtuUeGq-8c7Es>Y'DiGN1Y?D<Bq4iNtGtcUC9#YdMeDkJ-2xcW-Yc6.-v#*hF,J8vGp5FVCxsR/G`j9_%)PD.G7rw+H\"\n    \"wRFvBkHV=Br#f@$$8rEHZ8d<B^MBnDdNSJC8$JgLBaL$HxVKSD*3s'5*e2=Bv#fUCgoM=BcZJjBpYpKFb/-)%F*8'.408gL/ulUC$,I&Fk/xUCmKOg31>5/G<0[,Mrd-ZG/8uVC(7,wG\"\n    \"1c`.G:vCU1$i3GHlq>lEki`]&UQ3N1,gpKFi-D#HVT#c%s`8NB2bFnBoa@?H1[6pD9A2eGP7*Q/^vusBu+;iFZ.v;-Jf(e$WBDVC'6l+$rS6H$&G`*H*kK[1)YQSD1#2*HcO0[H49%`&\"\n    \"#WXt%4)ddG1#kjE_>=UCG`lO1xRdoD@m7bF3Y*bEw2]UC;aN4NEl1HM$nh?HaJV='e38kO-5kjEmNx>-Wc-x-.-/gLE4.SD*Ch-Oe'Go0&OHlE`9tB%'))iF';^Z$/5vLFgR%ZnBtHQ8\"\n    \":IwM1<G(4+[p[;%lR(W%d+Gv$,P>w$8>vhFa)gjB3/XZ14pN<Bpl`YGxJcGD(BqW_P4vlE/Y7fG`m[TCCg7bFjb1eG&*FnDmAXVCh4KKFq]FN1$'4RD50.%'*g@qC2wh_&]C'PNx^=d(\"\n    \"US1j(IcKHM%'9$P<>5/Gmn1-MD<?Z$t)/YB#b'gGnseQDr0)*Ho>5gC(dXVCt@idGg<MtBJ6n?8@AZ%H=CRFHwwOVC$jq`El#(c$-+4cH`l>kE`StW%,/r*HA4o+HuVoc4C&8bFo_,-G\"\n    \"vM'kElAGgC5c`.G?+f(%2kEs-n,lpLF0%oDX`0[Hx?>F%Au`='<>_oD&jTSD7/C8D#:SMF7H[rL9)8qL`1rjE]2S=B]94b$8j+vBrCHoD)BmH.+xO;(2=2^Q#af-D+^KkE=wElEOK*u(\"\n    \"@(Ku(6[%iF%5/B&k5FVCCI*hFAT=dM4>5/GM^;dEoxr]&[u0_G&>.FHjh>lE=lI+HNCXn-(%9I$?CpTC1*xGM0fipLBCJ;%j0f/N&4pfL)&Jc$sMkVCpl=>Bw+Z1F,,NM-X%15%AN'A&\"\n    \"4a?T.7o.G$+oRFH&h7FHsV,-Gq7sXB)^#lE^f#kE$^pgFg;6[&uANn3u2jXB-5,KCt0)=Bm;;X'-+4cHBhUh.pE;9CZ_U68Eui]HFGRV1tOovG/jTSD.m#hFu@SvG/HxuBbZ+F$H.k,5\"\n    \"c1FrC[K'C%2imlE*fJ^&p)fUCMw*_I/N`a/&&_kErGX7Dni^-6E_7FH8g7bF(s-rLH%IKF`SH&Fm8tnDnZq[-G'S?gChPUC:.v@.lY(HDk)Op7(HkM(,]>e?:h3cHP&c58Q3VDFEJ)=-\"\n    \"iDFR-Y#GZ-vJ]o3=$kCIB:ae-g]tS&pYt051m__&[:b4Nq18n0hnL*H8lV.GhR,-GBmN>HOxHa.%`%iFaxBS-UcFo$k6vAG7mXVCFF$dM*T@u/x-LoD-/2eGQM?9/q'Q-GV,LQ8FO3N1\"\n    \"nov`%9s'<-2))6&@3+D%8j8b@4F'jC?`4,/2l?&F+:(@'=)00FjH;9CxdE$JtocdG*+f(%jW76DRrXHM,wcQDhg[UChN9_%25v1Ft5kjE_ue:C5v)IHK[#dEi$nm%gY*dEQ_4k)s,adG\"\n    \"3V9?$.fV.GkaMb4CR7fGgJbQD4;.V1(8$PEe>ucDsYD]&[Lnp.268/GG;FIts(ZvG4l+(&7I.eG%>2eG:2HAJGd1U1qBDtBj4-oD6`&KDwcr9(hR:0Etx>vGr>9kE.Hpa>Rm5bFw-VeG\"\n    \">K(_I,HX7D3pKSDtR&ZGf`5-0m5S=B'9gKF;0aB%1$Bp.3g@qCMf5;)6D+7DJC/[P>>5/G2M]4C(QCc$/;-lE3@7*H1PU2BxYPhFD>[WACFd6Bo)0NB:]7+HrM$@&vV'oD9`r*HLHlC&\"\n    \"9wJZG?e>T%B>$t-5G%7MGpxv$wxg;-]^(]$c8tN1mYbUCC#rU1CgOdMXanI-t^/k&aUa*,TvJO9DwSQ(IaSK:7vM<%)PD.G)7C8)R#XDN[5U0M;E,[P>A5/G4*GU%;D+7Di&TJCv25,D\"\n    \"oU]VHhpkcDrM1)E-VaYGj&LDEsjWMBfWxfChs^$&cH/<-vV6i$;f0SD1[&*H.g3]'A,3kN3d&iFT#48MMB.eMZ[G-MTnn6//ToUC;XC6MO?rHM`hP-M9,v;HD:Is-Evt)NP@Kg/:Q4cH\"\n    \"*h`TC;&l;-9[@q.x?\\?LFs*9I$CE8p&-%wP10Pw#JqBViF3(0`I%SA>B9d7bF-KbrC*>W&&8h$=(B#/>Bjo>kE#2ieGZ1gKFm37FHuMbNE@]-bN-d@Y/+t;2Fr:A>'Ij]U)>trhF2.f6B\"\n    \"DOkCIF$kCI8jNx'ah>iO6XcUCCodBODW[oDoYZD%J<7rLL-OD%pL5nW1?=b$2r*cH%J%eG_hcWBn.8vG3s4VC#n3cH]q@n$>NbfG&8vhFc=T0FZE+F$(:vV%`Ew?H-]w#J*$WMF3rH&F\"\n    \"5fj*%64`dG$Yn'IdIeaHoe`PEoL=nDnI&ZG&>Rh#xOo=B0i)UD_V&&8,:gE#P)gk9:Li`F?*,d;0pH-db]F-Mu^20CWo5($2%&9In29kEe^nmD,r)pDQ?W%8)*h#$;x+?'olig1@',wG\"\n    \"i0iTCLkIbHPQ%rL[6K=BO.O*<l[>qrFN+jF2S@fGvl6)%,gpKFq[FWHk%61/<i7FH,Ynguc%5#9(VtmBt01pIw=;iFemtg$ve&3Cs=S>'/Ms*%hG1k(Cu;2FxC.bH0bZ*&G]8N0c.9kE\"\n    \"t`YhFuvA/CbTt'%548/GbML)E1,-lEZ5J=B%6J>BYWofCK86N9;R8]$pS^kE]>o=B.4x.Gu/(G$og`TC.:R20fp[TCja@uB$bPF%Xn_Z$'Rd<B&=^e$N5#>%-G3$J[<f*$_sKG$0)?pD\"\n    \"tnFVCcsCn<6snoDrV#0Cup2=B/)ddG/:]iF$L;tB.jF;Cf_CEHgP(*Hc`BnD=ZR'G5T7bFdY_5/6W+;CPfFHM>8(_I0#rU146r$'NHkCI0cDiFLGKPN90w0FpO(N1C%[h,(X`DN9Q]aH\"\n    \"=psON2a*pD&(c$'Bu3nB4K1U1wX)pD,wR,M:Q2VCxww*HgEV9Ck]HaE0Q1U1*HX7Dr%4Z%U'oFHg.sYGh)9kEm0D.Go8$@&D/05Np0gfL'QAHDdg[UCA+vUC:=G<HkWiTC=4;<IoGpgF\"\n    \"dX$)%L`>WIwRs#GDfd*.1pM=B9/HBOJH5bFp<r*HHkg%JRHAV1-g>LFX,d<BgDHD%>QU<_4.3&&nk`8.vbO;(f:hwK_n^MBkZ'_%+d]YBFg7bF3/$&JhR>LF-8vlEoVUG$2&C8D%LENM\"\n    \"MvY;HRIZEe+F-WC9Zx,M^_Y@0x_2pDas]jBUj7O4_?.w$4o[/G@dK68e;BO1*Q#lEh,BjB>*+pD20ogL#LT=B8A2eGj,+;C8I7q.sAouB:kE*[67f5Bx%a&&tRr'8MM0$H9Av-GZ#]TC\"\n    \")-H'63Nw&O>OTO1)LbfGkM?@&w&a9C;c`.Gw_s#G&ieFHEtNcHo#^NB1;USD:f<W1da[UCg4FVC))C`$)CHoD:)29.rq>LF0@Hv$udg,.4pkdMx/0o%6/o6D<Q7bFnRx;HENiDF8p;@8\"\n    \"jk0RB'a:dD8DQhFv&t2Bt%T6WV0=GHDjR*$uim`%q,KKF'^TSD)T,&Jgm*G3k1fY'(DmLFp>=;C&g9kEp/g/CHDRnBiKB_%6FOcHi?%UCNVVn3#aF'%oIP#H/VHSDi#b%H(8iaH$fovG\"\n    \",8HlE3p#pD*oSvG3JDEH-sFt%$i3GHM$obH3ku'&(rem/Y82=B(?]:CuY/032n0,HFGO$Ho;FVC)l%iFS#=SM;XmvG*q%UCO*+pDro1HD^_M[%ppc<B#8hVC)aUG$-`n+Hp*2eG='h%J\"\n    \"wI/>B'*8UC#g1eGAL`T.=CRFHW>1@-6eXg$]:o344bV8&UsEX(YQY3F15]UC]2+gMHmHwHM?HKDsH.bH$aDA&Mb>dE+%cV(;8`m/tvEnDi&kjE#pm*&=0l8I*l*,HlPq(%upIvH3^+HM\"\n    \"b]ElEEg4HM;)ooDm&:,$VEtB%s*vsBp&Cc$L)K^4uOAvG)3]>BvYkUC)S;2F9vFnBwswmD,GiiF-4S.GG;.V17rI+HxMd`%,gpKF$i3GH(tR/GpeC?H)ow+H`ZD<B]X08/P65bHD`HFN\"\n    \"3WRSD8N1U1e-:X1;kn+H[j$KDgY`t'rhRL,<V3x'81D.G6f3'F8;si-7r<tU9_@Y%=$paH@%8fGl+=3E8MeV17=4cH49.%'WrnRM1PmvG%*bNER00iF?/HBOIE5bFs:uT1bsuW'27O2C\"\n    \"[O;nNJ'%kEd?/jB(HxUCkPAfEgWiTC3BQ<BiDCHD7/(8D-fw+HXO?'O;c:GH$coY'DkTJD=GY5'C_tMC2WBaNg5M]$8DJuB%k'P<9h]Q(pAfHD/e1qL2ho*HPB8_A9Dnw'C30@J8HeNN\"\n    \"R2#/Gc`pP'E.]0u#QdMC:3=o4#]rdGsfpoD::FnB2A)iFo/,,DcPk6DYJHm/)=_oD%&@'IBQF$/s[gKFN_)be5]BOE:#+A'[Bx8.<SeV1M:xMCGV0sL>(+'Gc92=BAkAvGjScdG_8bQD\"\n    \"-BoUCm-VeG,40`InR4VCrf?eD3A2eGx1u413YHlE2;2eGt_9kE_HZi4qA_(%.%fFH.rK&4m@7`IYGV=B5>Su'jQfs-MpwrL)a*bN5dKW$hlg7:Ddh?HAmJ-PF^BW$6YCdD4%4,H5A3E%\"\n    \":/@V1uJZ%&F)X#H+YI+H+fPW-skJe$>J7N0oJmw&&5H1FCpnrLHE5bFvs3cH>45sHA_LaF]DM=B1rd9Dp%PgC.EvfD>`9#H78Qt$05'oDap]JCdDVt'0G?x%Tqd6Bp2KjBq^IUCg<+F$\"\n    \"2cw^IxQ7fGH*>BI.MZ1FuT0,HuH=fG%?+vBMBGbH&8[&F*a'kEsmX'%+a^oDg:&$G(#PVC(Dq;-DhI6/>qovGS)b4NJ^EBOB05bFQeSV%r876DI<'k018iEHhb(*Htp76DgQeZH1c;iF\"\n    \"nmJNBU-7B4viO,D$'N=BxZF/Gg#OnD-/2eG?rIrL5C>+HtmE(IqVM9(tBb20*=f6BnlL*H6>mQUigQT-CXl`'BwIc$ur>LF4STauitoTC'KCm/)l0S)@xnbH/mWO7=4ffGGpR'G$HxUC\"\n    \"ai.>Bv2fUC1ew+H3GqoDC6;eEM/NPC&HX7D[jX,H3M@+H%mnUCo$Q<BFneoDpj-O:rraN1*jXVC3dFVCq5An0Rvc<BcrGkE^H'C%QBwM1Q/<Y1-erhF+g^#I/j*pDiJ5hFS.c586xrW%\"\n    \",Z,-GplCEH<C%6/:fPhFMV$bN$]t_$:cBnDU(fV1$krTC.O=jFv7<&&(ET0F'>dlEmisqgkXi69om@p&>OVN8bO4U&kj[:CwpNNE2k#>'A7*9.,gpKF[wh,MXm5bFnq>LFivYw&k`(eG\"\n    \"Gx[V1%/$PE?:mW-dF1l+(JcdGYX`.MB-5bFf0S/:*.x5'9>2eG&4-gL7(kN0i>+:C#t:9C$n7gLWY_@-=-Kg16:W>G1</>BpCFVCFD&qLf>DnBkYQ`%$teUCwJ00FuA83/5;Z1F)6`0>\"\n    \":@vlEEJt=(pY,$P<r&=B?`D_OeBM2%HIp:)J1D.G5rAvG-)uVC^BD<Bx(N#GgkP<Bg7oH;khWN1))?pD/):WCE$$gDE/m<-S)hS/8%=GHwJZw&?RFmB-gOVCVTr$'B<F`%-$7rLwgA.G\"\n    \"ZvAW4xUeEH(aucD_6bB%(NkVC-A3E%9Qw7MH?c&F'AViFtxu-G*X2iF$RM=B;Q7bF268/GDme7MeIKA&&LQmhqDF&F-4bcH6g*rLrcc:C?)CEN7oc6BwflgC^WN@8VG)W%(3c^%EffYB\"\n    \"_M0nD-fDiFgpOgC(QpKFa$Q<B#k*cHAGJuBkf[:(lB`TCtZr=B1C-.%:YW=(-%luBCfmlEs4Ne$2'FbH+5_kE,?XdM'4xKDp)$@&4I+,H,gpoDm#^/C(m#hF6Qt)Neru%0q-DEH.,vLF\"\n    \"9XHk%8c^oDk203B0(o'I@R]/Gid+KC-s1eGsVqC%%Q4ZBev'C%mk><Bu5-%&UHwM185l3+T)'iF#>;MF)0bV$wj;?$?]`.G5,HT%4D6@&rp%UCr&sXBf1s0:P8o*F*sOVC&p1eGU))XB\"\n    \"liRu'047Q8fa;w$,B4VCf%sYG'>BW2g=b7D+5QpDbxGkE2E1U1AiNj0xitUC5T'kE'si9(m$&7N;f3rL,e#+H2KoFHscH`%ggaNEo7w#JkecdGxf9kEa]/n$HD+-Go.)LFtTx*$s8q(%\"\n    \"#5D.Ga>L)E.d'oD2<m%J'dTSDk&U_%/].+Hi)4VCq$DEHOx3W1u2U_%0s'WCkB`9Cn*;iFGCffGAL$ed^[k?HP<7#H>:ka%,rgnDnB.UCd/^JCuoMa%.HtnDjs@>BfX#1FnY0nDu5A>B\"\n    \"sZiTCWE<2B>9&gLoUa<BuNP,2&ZfYB2jtGHs]Z%&n)fQDwr4ZH*YDlEZU>*Fq6SMF*'s=BV<+[gZxXVC/Fx.G98rU1c?DtBpX%iFx=&vGu5>gCACViF&N)I.$BoUC9QUmB%bVeG%Vnq$\"\n    \"c`O<h/t7t%QfRV1/,ZhF/-J>%JHOGH'?76MpH[oDH`d*.Pa^x&so(*H)W>-G7rw+Hhw$n8QZZ$$_W0c$.s'oDl0XbHN+9PC/:S.G2UFnB&3fUC0(o'Ip-4fGa)Qw&l8ZMC[.=0Dh5_$&\"\n    \".;qOE_M^Y%k5N2B+T^0FlnuhF/7=GHaJV='tocdGi)00FfN%UCseeaH&=d<Bk:@p.r:uT12+Xe$9EC6MrK>uB8X@U.2F'OCHjGW-DdJR*0@We$GsL6M3'DVCK,X8M'U5>BM>X#Hp5FVC\"\n    \"kdvI3:GViFr$vLFMf<W1pm.:Cev8jB`xF'GbSV=B3F+RB'^;x&_d<N1l()LFUSg,&'Ym)%%f_p0%2`HD=g1U1*AhoDV_1FFhs7=BpMQ&Fmd2=Buj@gLjuYGE2%jMF-WX,Hx(wAFxW;tB\"\n    \"ri$d$8];2Fs'AiF:MDeGEo7Y-^'?b7(w8I$VqhjE&]DPEh5_$&18iEHb3m<Bc%UVC,rj-$H>s=B9A2eG%.SMF*5Rd$-VmLFu4n0#L,P:v%)###TQj-$ePb-TSbNj04+0oQ#####54K4R\"\n    \"m:Pse(#)##\";\n\n"
  },
  {
    "path": "src/fps_limiter.h",
    "content": "#pragma once\n#include \"overlay_params.h\"\n#include <mesa/util/os_time.h>\n\nclass fpsLimiter {\n    private:\n        int64_t target = 0;\n        int64_t overhead = 0;\n        size_t fps_limits_idx = 0;\n        int64_t frame_start = 0;\n        int64_t frame_end = 0;\n\n        int64_t calc_sleep(int64_t start, int64_t end) {\n            if (target <= 0 || start <= 0)\n                return 0;\n\n            int64_t work = start - end;\n            if (work < 0)\n                work = 0;\n\n            int64_t sleep = (target - work) - overhead;\n            return sleep > 0 ? sleep : 0;\n        }\n\n        void do_sleep(int64_t sleep_time) {\n            if (sleep_time <= 0)\n                return;\n\n            int64_t t0 = os_time_get_nano();\n\n            std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_time));\n\n            int64_t over = (os_time_get_nano() - t0) - sleep_time;\n            if (over < 0 || over > (target / 2))\n                over = 0;\n            \n            overhead = over;\n        }\n\n    public:\n        bool use_early;\n        bool active = false;\n\n        fpsLimiter(bool use_early) : use_early(use_early) {\n            auto& fps_limit = get_params()->fps_limit;\n            if (fps_limit.empty())\n                return;\n\n            active = true;\n\n            float tar = fps_limit[fps_limits_idx];\n            target = tar <= 0.0f ? 0 : int64_t(1'000'000'000.0f / tar);\n        }\n\n        void limit(bool is_early) {\n            if (!active || target <= 0)\n                return;\n\n            frame_start = os_time_get_nano();;\n\n            if (is_early != use_early) return;\n\n            int64_t sleep_time = calc_sleep(frame_start, frame_end);\n            if (sleep_time > 0)\n                do_sleep(sleep_time);\n\n            frame_end = os_time_get_nano();\n        }\n\n        void next_limit() {\n            auto& v = get_params()->fps_limit;\n            if (v.empty())\n                return;\n\n            fps_limits_idx = (fps_limits_idx + 1) % v.size();\n            auto next_target = v[fps_limits_idx];\n            target = next_target <= 0.0f ? 0 : int64_t(1'000'000'000.0f / next_target);\n            SPDLOG_DEBUG(\"Changed fps limit to {}\", next_target);\n        }\n\n        int current_limit() {\n            auto& v = get_params()->fps_limit;\n            return v[fps_limits_idx];\n        }\n};\n\nextern std::shared_ptr<fpsLimiter> fps_limiter;\n"
  },
  {
    "path": "src/fps_metrics.h",
    "content": "#pragma once\n#include <vector>\n#include <string>\n#include <memory>\n#include <thread>\n#include <mesa/util/os_time.h>\n#include <numeric>\n#include <mutex>\n#include <algorithm>\n#include <condition_variable>\n#include <stdexcept>\n#include <iomanip>\n#include <spdlog/spdlog.h>\n\nstruct metric_t {\n    std::string name;\n    float value;\n    std::string display_name;\n};\n\nclass fpsMetrics {\n    private:\n        std::vector<float> frametimes;\n        std::thread thread;\n        std::mutex mtx;\n        std::condition_variable cv;\n        bool run = false;\n        bool thread_init = false;\n        bool terminate = false;\n        bool resetting = false;\n        size_t max_size = 10000;\n        std::vector<metric_t> metrics;\n\n        void _thread() {\n            thread_init = true;\n            while (true){\n                std::unique_lock<std::mutex> lock(mtx);\n                cv.wait(lock, [this] { return run; });\n\n                if (terminate)\n                    break;\n\n                calculate();\n\n                run = false;\n            }\n        }\n\n        void calculate(){\n            if (frametimes.empty())\n                return; \n\n            std::vector<float> sorted_values = frametimes;\n            std::sort(sorted_values.begin(), sorted_values.end(), std::greater<float>());\n\n            auto it = metrics.begin();\n            while (it != metrics.end()) {\n                if (it->name == \"AVG\") {\n                    it->display_name = it->name;\n\n                    float sum = 0.0f;\n                    for (const auto& f : sorted_values)\n                        sum += f;\n\n                    float avg = 1000.f / (sum / sorted_values.size());\n                    it->value = avg;\n                } else {\n                    try {\n                        float val = std::stof(it->name);\n                        if (val <= 0.0f || val >= 1.0f) {\n                            SPDLOG_DEBUG(\"Failed to use fps metric, it's out of range {}\", it->name);\n                            it = metrics.erase(it);\n                            continue;\n                        }\n\n                        // Format display name as a percentage\n                        float multiplied_val = val * 100;\n                        std::ostringstream stream;\n                        stream << std::fixed << std::setprecision(multiplied_val == static_cast<int>(multiplied_val) ? 0 : 1)\n                               << multiplied_val << \"%\";\n                        it->display_name = stream.str();\n                        uint64_t idx = val * sorted_values.size() - 1;\n                        if (idx >= sorted_values.size())\n                            break;\n\n                        it->value = 1000.f / sorted_values[idx];\n                    } catch (const std::invalid_argument& e) {\n                        SPDLOG_DEBUG(\"Failed to use fps metric value {}\", it->name);\n                        it = metrics.erase(it);\n                        continue;\n                    }\n                }\n                ++it;\n            }\n        }\n\n        std::vector<metric_t> add_metrics_to_vector(std::vector<std::string> values) {\n            std::vector<metric_t> _metrics;\n            for (auto& val : values){\n                for(char& c : val) {\n                    c = std::toupper(static_cast<unsigned char>(c));\n                }\n                _metrics.push_back({val, 0.0f});\n            }\n            return _metrics;\n        }\n\n    public:\n        fpsMetrics(std::vector<std::string> values){\n            metrics = add_metrics_to_vector(values);\n\n            if (!thread_init) {\n                thread = std::thread(&fpsMetrics::_thread, this);\n                // \"mangohud-fpsmetrics\" wouldn't fit in the 15 byte limit\n                pthread_setname_np(thread.native_handle(), \"mangohud-fpsmet\");\n            }\n        };\n\n        fpsMetrics(std::vector<std::string> values, std::vector<float> only_frametime) {\n            metrics = add_metrics_to_vector(values);\n            for (auto& frametime : only_frametime)\n                frametimes.push_back(frametime);\n\n            calculate();\n        };\n\n        void update(float new_frametime) {\n            if (resetting)\n                return;\n\n            if (new_frametime > 100000) return; // Ignore extremely long frames\n\n            // lock before modifying vector\n            std::lock_guard<std::mutex> lock(mtx);\n\n            if (frametimes.size() >= max_size)\n                frametimes.erase(frametimes.begin());\n\n            frametimes.push_back(new_frametime);\n        }\n\n\n        void update_thread(){\n            if (resetting)\n                return;\n\n            {\n                std::lock_guard<std::mutex> lock(mtx);\n                run = true;\n            }\n            cv.notify_one();\n        }\n\n        void reset_metrics(){\n            resetting = true;\n            while (run){}\n            frametimes.clear();\n            resetting = false;\n        }\n\n        std::vector<metric_t> copy_metrics() {\n            std::lock_guard<std::mutex> lock(mtx);\n            return metrics;\n        }\n\n        ~fpsMetrics(){\n            terminate = true;\n            {\n                std::lock_guard<std::mutex> lock(mtx);\n                run = true;\n            }\n            cv.notify_one();\n            if (thread.joinable())\n                thread.join();\n        }\n};\n\nextern std::unique_ptr<fpsMetrics> fpsmetrics;\n"
  },
  {
    "path": "src/ftrace.cpp",
    "content": "#include \"ftrace.h\"\n\n#ifdef HAVE_FTRACE\n\n#include <algorithm>\n#include <climits>\n#include <fcntl.h>\n#include <poll.h>\n#include <unistd.h>\n#include \"mesa/util/macros.h\"\n#include \"string_utils.h\"\n\nnamespace FTrace {\n\nFTrace::FTrace(const overlay_params::ftrace_options& options) {\n   assert(options.enabled);\n\n   trace_pipe_fd = open(\"/sys/kernel/tracing/trace_pipe\", O_RDONLY | O_NONBLOCK);\n   if (trace_pipe_fd == -1) {\n       SPDLOG_ERROR(\"could not open ftrace pipe: {}\", strerror(errno));\n       return;\n   }\n\n   thread = std::thread(&FTrace::ftrace_thread, this);\n   pthread_setname_np(thread.native_handle(), \"mangohud-ftrace\");\n\n   for (auto& tp : options.tracepoints) {\n      data.tracepoints.push_back(tp);\n      collection.map.emplace(tp, Tracepoint::CollectionValue { });\n\n      switch (tp->type) {\n      case TracepointType::Histogram:\n         SPDLOG_DEBUG(\"ftrace: will collect tracepoint '{}' for histogram display\",\n                      tp->name);\n         break;\n      case TracepointType::LineGraph:\n         SPDLOG_DEBUG(\"ftrace: will collect tracepoint '{}' (parameter '{}') for line graph display\",\n                      tp->name, tp->field_name);\n         break;\n      case TracepointType::Label:\n         SPDLOG_DEBUG(\"ftrace: will collect tracepoint '{}' (parameter '{}') for label display\",\n                      tp->name, tp->field_name);\n         break;\n      default:\n         SPDLOG_ERROR(\"ftrace: unknown tracepoint type for tracepoint '{}'\",\n                      tp->name);\n      }\n   }\n}\n\nFTrace::~FTrace()\n{\n    stop_thread = true;\n    if (thread.joinable())\n        thread.join();\n\n    if (trace_pipe_fd != -1)\n        close(trace_pipe_fd);\n}\n\nvoid FTrace::ftrace_thread()\n{\n    struct {\n        std::array<char, 4096> data;\n        size_t size { 0 };\n    } buffer;\n\n    while (!stop_thread) {\n        struct pollfd fd = {\n            .fd = trace_pipe_fd,\n            .events = POLLIN,\n            .revents = 0,\n        };\n        int ret = poll(&fd, 1, 500);\n        if (ret < 0) {\n            SPDLOG_ERROR(\"FTrace: polling on trace_pipe failed: {}\", strerror(errno));\n            break;\n        }\n\n        if (!(fd.revents & POLLIN))\n            continue;\n\n        ssize_t size_read = read(trace_pipe_fd, &buffer.data[buffer.size], buffer.data.size() - buffer.size);\n        if (size_read < 0) {\n            SPDLOG_ERROR(\"FTrace: reading from trace_pipe failed: {}\", strerror(errno));\n            break;\n        }\n        buffer.size += size_t(size_read);\n\n        {\n            char *it = buffer.data.begin();\n            char *end_it = std::next(it, buffer.size);\n\n            while (std::distance(it, end_it)) {\n                char *newline_it = std::find(it, end_it, '\\n');\n                if (newline_it == end_it)\n                    break;\n\n                handle_ftrace_entry(std::string { it, size_t(std::distance(it, newline_it)) });\n                it = std::next(newline_it, 1);\n            }\n\n            buffer.size = std::distance(it, end_it);\n            if (buffer.size)\n                std::move(it, end_it, buffer.data.begin());\n        }\n    }\n}\n\nstatic std::string get_field_value(std::string fields_str, std::string target_field_name)\n{\n   // Parsing print-formatted ftrace entries isn't ideal because there's no standardized\n   // way of reporting trace event fields. ftrace will also print out numerical values\n   // in both decimal and hexadecimal. It's still the simplest approach as otherwise we'd\n   // have to wrangle with raw trace data that we don't have access to, and trace event\n   // field formats that are hard to define and apply.\n\n   // Most common print format is `field=value`, with `value` possibly containing spaces.\n   // Iteration below accounts for that and returns the field value for the desired name,\n   // if present.\n\n   auto fields_data = str_tokenize(fields_str, \" \");\n   for (auto it = fields_data.begin(); it != fields_data.end();) {\n      auto assign_pos = it->find('=');\n      if (assign_pos == std::string::npos) {\n         ++it;\n         continue;\n      }\n\n      auto field_name = it->substr(0, assign_pos);\n      auto field_value = it->substr(std::min(it->size(), assign_pos + 1));\n\n      ++it;\n      while (it != fields_data.end()) {\n         if (it->find('=') != std::string::npos)\n            break;\n\n         field_value += \" \" + *it;\n         ++it;\n      }\n\n      if (field_name == target_field_name)\n         return field_value;\n   }\n\n   return { };\n}\n\nvoid FTrace::handle_ftrace_entry(std::string entry)\n{\n   std::unique_lock<std::mutex> lock(collection.mutex);\n\n   for (auto& collection_entry : collection.map) {\n      auto& tp = collection_entry.first;\n\n      // Search for the tracepoint name in the entry. It's expected either\n      // at the beginning of string or with a space before it.\n      auto name_pos = entry.find(tp->name + \":\");\n      if (name_pos == std::string::npos)\n         continue;\n      if (!(name_pos == 0 || (name_pos > 0 && entry[name_pos - 1] == ' ')))\n         continue;\n\n      // Remainder of entry is field data. We use it as necessary,\n      // depending on the tracepoint type.\n      auto fields_str = entry.substr(name_pos + tp->name.size() + 1);\n\n      switch (tp->type) {\n      case TracepointType::Histogram:\n         collection_entry.second.f += 1;\n         break;\n      case TracepointType::LineGraph:\n      {\n         auto field_value = get_field_value(fields_str, tp->field_name);\n         if (!field_value.empty()) {\n            char *value_end;\n            uint64_t value = strtoull(field_value.c_str(), &value_end, 16);\n\n            if (value != ULLONG_MAX)\n               collection_entry.second.f += (float) value;\n         }\n        break;\n      }\n      case TracepointType::Label:\n      {\n         auto field_value = get_field_value(fields_str, tp->field_name);\n         if (!field_value.empty())\n            collection_entry.second.field_value = field_value;\n         break;\n      }\n      default:\n         UNREACHABLE(\"invalid tracepoint type\");\n      }\n   }\n}\n\nvoid FTrace::update()\n{\n   auto update_index = ++data.update_index % Tracepoint::PLOT_DATA_CAPACITY;\n   for (auto& tp : data.tracepoints) {\n      tp->update_index = update_index;\n\n      // Iterate over the stored plot values often enough to keep\n      // the data range updated and plot presentation visually useful.\n      if (!(update_index % (Tracepoint::PLOT_DATA_CAPACITY / 4))) {\n         auto max = tp->data.plot.values[0];\n         for (auto v : tp->data.plot.values)\n            max = std::max(max, v);\n\n         tp->data.plot.range = { 0, max };\n      }\n   }\n\n   std::unique_lock<std::mutex> lock(collection.mutex);\n\n   for (auto& it : collection.map) {\n      auto& tp = it.first;\n      auto& value = it.second;\n\n      switch (tp->type) {\n      case TracepointType::Histogram:\n      case TracepointType::LineGraph:\n      {\n         tp->data.plot.values[tp->update_index] = value.f;\n         auto max = std::max(tp->data.plot.range.max, value.f);\n         tp->data.plot.range = { 0, max };\n         break;\n      }\n      case TracepointType::Label:\n      {\n         if (!value.field_value.empty())\n            tp->data.field_value = value.field_value;\n         break;\n      }\n      default:\n         UNREACHABLE(\"invalid tracepoint type\");\n      }\n\n      value = { };\n   }\n}\n\nfloat FTrace::get_plot_values(void *data, int index)\n{\n   const Tracepoint& tp = *((const Tracepoint *) data);\n   return tp.data.plot.values[(index + tp.update_index + 1) % Tracepoint::PLOT_DATA_CAPACITY];\n}\n\nstd::unique_ptr<FTrace> object = nullptr;\n\n} // namespace FTrace\n\n#endif // HAVE_FTRACE\n"
  },
  {
    "path": "src/ftrace.h",
    "content": "#pragma once\n\n#ifdef HAVE_FTRACE\n\n#include <array>\n#include <atomic>\n#include <memory>\n#include <thread>\n#include <unordered_map>\n\n#include <spdlog/spdlog.h>\n\n#include \"overlay_params.h\"\n\nnamespace FTrace {\n\nenum class TracepointType {\n    Histogram,\n    LineGraph,\n    Label,\n};\n\nstruct Tracepoint {\n    uint32_t update_index { 0 };\n    std::string name;\n    TracepointType type;\n    std::string field_name;\n\n    static constexpr unsigned PLOT_DATA_CAPACITY = 200;\n\n    struct CollectionValue {\n        float f { 0 };\n        std::string field_value;\n    };\n\n    struct {\n        struct {\n            std::array<float, PLOT_DATA_CAPACITY> values;\n            struct {\n                float min { 0 };\n                float max { 0 };\n            } range;\n        } plot;\n        std::string field_value;\n    } data;\n};\n\nclass FTrace {\nprivate:\n    int trace_pipe_fd { -1 };\n\n    std::thread thread;\n    std::atomic<bool> stop_thread { false };\n\n    void ftrace_thread();\n    void handle_ftrace_entry(std::string entry);\n\n    struct {\n        std::mutex mutex;\n        std::unordered_map<std::shared_ptr<Tracepoint>, Tracepoint::CollectionValue> map;\n    } collection;\n\n    struct {\n        std::vector<std::shared_ptr<Tracepoint>> tracepoints;\n        uint32_t update_index { 0 };\n    } data;\n\npublic:\n    FTrace(const overlay_params::ftrace_options& options);\n    ~FTrace();\n\n    void update();\n\n    const std::vector<std::shared_ptr<Tracepoint>>& tracepoints() { return data.tracepoints; }\n\n    static float get_plot_values(void *data, int index);\n};\n\nextern std::unique_ptr<FTrace> object;\n\n} // namespace FTrace\n\n#endif // HAVE_FTRACE\n"
  },
  {
    "path": "src/gl/gl.h",
    "content": "#pragma once\n#ifndef MANGOHUD_GL_GL_H\n#define MANGOHUD_GL_GL_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif //__cplusplus\n\nvoid * glXCreateContext(void *, void *, void *, int);\nvoid glXDestroyContext(void *, void*);\nvoid glXSwapBuffers(void*, void*);\nvoid glXSwapIntervalEXT(void*, void*, int);\nint glXSwapIntervalSGI(int);\nint glXSwapIntervalMESA(unsigned int);\nint glXGetSwapIntervalMESA(void);\nint glXMakeContextCurrent(void*, void*, void*, void*);\nint glXMakeCurrent(void*, void*, void*);\nvoid *glXGetCurrentContext();\nvoid *glXGetCurrentDrawable();\nvoid *glXGetCurrentReadDrawable();\nvoid *glXCreateContextAttribsARB(void *dpy, void *config,void *share_context, int direct, const int *attrib_list);\n\nvoid* glXGetProcAddress(const unsigned char*);\nvoid* glXGetProcAddressARB(const unsigned char*);\nint glXQueryDrawable(void *dpy, void* glxdraw, int attr, unsigned int * value);\n\nint64_t glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder);\n\nunsigned int eglSwapBuffers( void*, void* );\nvoid* eglGetPlatformDisplay( unsigned int, void*, const intptr_t* );\nvoid* eglGetDisplay( void* );\nunsigned int eglDestroyContext( void*, void* );\nvoid* eglGetProcAddress( const char* );\nint eglTerminate( void* );\n\n#ifdef __cplusplus\n}\n#endif //__cplusplus\n\n#endif //MANGOHUD_GL_GL_H\n"
  },
  {
    "path": "src/gl/gl_hud.cpp",
    "content": "#include <cstdlib>\n#include <functional>\n#include <thread>\n#include <string>\n#include <iostream>\n#include <sstream>\n#include <memory>\n#include <unistd.h>\n#include <spdlog/spdlog.h>\n#include <imgui.h>\n#ifdef __linux__\n#include <implot.h>\n#endif\n#include \"imgui_utils.h\"\n#include \"gl_hud.h\"\n#include \"file_utils.h\"\n#include \"notify.h\"\n#include \"blacklist.h\"\n\n#include <glad/glad.h>\n\n\n#define GLX_RENDERER_VENDOR_ID_MESA                      0x8183\n#define GLX_RENDERER_DEVICE_ID_MESA                      0x8184\n\n#ifdef HAVE_X11\nbool glx_mesa_queryInteger(int attrib, unsigned int *value);\n#endif\n\nnamespace MangoHud { namespace GL {\n\nstruct GLVec\n{\n    GLint v[4];\n\n    GLint operator[] (size_t i)\n    {\n        return v[i];\n    }\n\n    bool operator== (const GLVec& r)\n    {\n        return v[0] == r.v[0]\n            && v[1] == r.v[1]\n            && v[2] == r.v[2]\n            && v[3] == r.v[3];\n    }\n\n    bool operator!= (const GLVec& r)\n    {\n        return !(*this == r);\n    }\n};\n\nstatic GLVec last_vp {}, last_sb {};\nswapchain_stats sw_stats {};\nstatic struct imgui_contexts imgui_contexts;\nstatic uint32_t vendorID;\nstatic std::string deviceName;\n\nstatic notify_thread notifier;\nstatic bool cfg_inited = false;\nstatic ImVec2 window_size;\nstatic bool inited = false;\noverlay_params params {};\n\n// seems to quit by itself though\nstatic std::unique_ptr<notify_thread, std::function<void(notify_thread *)>>\n    stop_it(&notifier, [](notify_thread *n){ stop_notifier(*n); });\n\nvoid imgui_init()\n{\n    if (cfg_inited)\n        return;\n\n    init_spdlog();\n    if (is_blacklisted())\n        return;\n\n    parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n\n   //check for blacklist item in the config file\n   for (auto& item : params.blacklist) {\n      add_blacklist(item);\n   }\n\n    if (sw_stats.engine != EngineTypes::ZINK){\n        sw_stats.engine = OPENGL;\n        if (lib_loaded(\"wined3d\", HUDElements.g_gamescopePid))\n            sw_stats.engine = WINED3D;\n        if (lib_loaded(\"libtogl.so\", HUDElements.g_gamescopePid) || lib_loaded(\"libtogl_client.so\", HUDElements.g_gamescopePid))\n            sw_stats.engine = TOGL;\n    }\n\n    is_blacklisted(true);\n    notifier.params = &params;\n    start_notifier(notifier);\n    window_size = ImVec2(params.width, params.height);\n    init_system_info();\n    cfg_inited = true;\n    init_cpu_stats(params);\n}\n\nvoid imgui_create(gl_context *ctx, const gl_wsi plat)\n{\n    //SPDLOG_DEBUG(\"ctx {}\", (void *)ctx);\n    if (!ctx)\n        return;\n\n    if (inited)\n        return;\n\n    imgui_init();\n\n    if (!gladLoadGL())\n        spdlog::error(\"Failed to initialize OpenGL context, crash incoming\");\n\n    deviceName = (char*)glGetString(GL_RENDERER);\n    // If we're running zink we want to rely on the vulkan loader for the hud instead.\n    if (deviceName.find(\"zink\") != std::string::npos)\n        return;\n\n    GetOpenGLVersion(sw_stats.version_gl.major,\n        sw_stats.version_gl.minor,\n        sw_stats.version_gl.is_gles);\n\n    std::string vendor = (char*)glGetString(GL_VENDOR);\n    SPDLOG_DEBUG(\"vendor: {}, deviceName: {}\", vendor, deviceName);\n    sw_stats.deviceName = deviceName;\n    if (vendor.find(\"AMD\") != std::string::npos\n    || deviceName.find(\"AMD\") != std::string::npos\n    || deviceName.find(\"Radeon\") != std::string::npos\n    || deviceName.find(\"NAVI\") != std::string::npos) {\n        vendorID = 0x1002;\n    } else if (vendor.find(\"Intel\") != std::string::npos\n    || deviceName.find(\"Intel\") != std::string::npos) {\n        vendorID = 0x8086;\n    } else if (vendor.find(\"freedreno\") != std::string::npos) {\n        vendorID = 0x5143;\n    }  else {\n        vendorID = 0x10de;\n    }\n\n    HUDElements.vendorID = vendorID;\n\n    uint32_t device_id = 0;\n#ifdef HAVE_X11\n    if (plat == gl_wsi::GL_WSI_GLX)\n        glx_mesa_queryInteger(GLX_RENDERER_DEVICE_ID_MESA, &device_id);\n#endif\n    SPDLOG_DEBUG(\"GL device id: {:04X}\", device_id);\n    sw_stats.gpuName = gpu = remove_parentheses(deviceName);\n    SPDLOG_DEBUG(\"gpu: {}\", gpu);\n    // Setup Dear ImGui context\n    IMGUI_CHECKVERSION();\n\n    if (!imgui_contexts.imgui)\n        imgui_contexts =  create_imgui_contexts();\n\n    auto saved_imgui_contexts = get_current_imgui_contexts();\n    make_imgui_contexts_current(imgui_contexts);\n\n    ImGuiIO& io = ImGui::GetIO(); (void)io;\n    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls\n    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls\n\n    // Setup Dear ImGui style\n    ImGui::StyleColorsDark();\n    //ImGui::StyleColorsClassic();\n    HUDElements.convert_colors(false, params);\n\n    glGetIntegerv (GL_VIEWPORT, last_vp.v);\n    glGetIntegerv (GL_SCISSOR_BOX, last_sb.v);\n\n    ImGui::GetIO().IniFilename = NULL;\n    ImGui::GetIO().DisplaySize = ImVec2(last_vp[2], last_vp[3]);\n\n    ImGui_ImplOpenGL3_Init(ctx);\n\n    create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary);\n    sw_stats.font_params_hash = params.font_params_hash;\n    inited = true;\n\n    // Restore global context or ours might clash with apps that use Dear ImGui\n    make_imgui_contexts_current(saved_imgui_contexts);\n}\n\nvoid imgui_shutdown(gl_context *ctx, bool last)\n{\n    //SPDLOG_DEBUG(\"destroying ctx {}, imgui_ctx {}, last {}\", (void *)ctx, (void *)state.imgui_ctx, last);\n    if (imgui_contexts.imgui) {\n        auto saved_imgui_contexts = get_current_imgui_contexts();\n        make_imgui_contexts_current(imgui_contexts);\n        ImGui_ImplOpenGL3_Shutdown(ctx);\n        make_imgui_contexts_current(saved_imgui_contexts);\n        if (last)\n        {\n            destroy_imgui_contexts(imgui_contexts);\n            inited = false;\n        }\n    }\n}\n\nvoid imgui_render(gl_context *ctx, unsigned int width, unsigned int height)\n{\n    //SPDLOG_DEBUG(\"imgui_ctx {}\", (void *)state.imgui_ctx);\n    if (!imgui_contexts.imgui)\n        return;\n\n    static int control_client = -1;\n    if (params.control >= 0) {\n        control_client_check(params.control, control_client, deviceName);\n        process_control_socket(control_client, params);\n    }\n\n    check_keybinds(params);\n    update_hud_info(sw_stats, params, vendorID);\n\n    auto saved_imgui_contexts = get_current_imgui_contexts();\n    make_imgui_contexts_current(imgui_contexts);\n\n    ImGui::GetIO().DisplaySize = ImVec2(width, height);\n    if (HUDElements.colors.update)\n        HUDElements.convert_colors(params);\n\n    ImGui_ImplOpenGL3_NewFrame(ctx);\n    ImGui::NewFrame();\n    {\n        std::lock_guard<std::mutex> lk(notifier.mutex);\n        overlay_new_frame(params);\n        position_layer(sw_stats, params, window_size);\n        render_imgui(sw_stats, params, window_size, false);\n        overlay_end_frame();\n    }\n\n    ImGui::Render();\n    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());\n\n    if (sw_stats.font_params_hash != params.font_params_hash)\n    {\n        sw_stats.font_params_hash = params.font_params_hash;\n        create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary);\n        // Previus texture is created in ImGui_ImplOpenGL3_CreateDeviceObjects in first call of ImGui_ImplOpenGL3_NewFrame\n        ImGui_ImplOpenGL3_DestroyFontsTexture(ctx);\n        ImGui_ImplOpenGL3_CreateFontsTexture(ctx);\n    }\n\n    make_imgui_contexts_current(saved_imgui_contexts);\n}\n\n}} // namespaces\n"
  },
  {
    "path": "src/gl/gl_hud.h",
    "content": "#pragma once\n#ifndef MANGOHUD_GL_IMGUI_HUD_H\n#define MANGOHUD_GL_IMGUI_HUD_H\n\n#include \"overlay.h\"\n#include \"gl_renderer.h\"\n\nnamespace MangoHud { namespace GL {\n\nenum gl_wsi\n{\n    GL_WSI_UNKNOWN,\n    GL_WSI_GLX,\n    GL_WSI_EGL,\n};\n\nvoid imgui_init();\nvoid imgui_create(gl_context *ctx, const gl_wsi plat);\nvoid imgui_shutdown(gl_context *ctx, bool last);\nvoid imgui_render(gl_context *ctx, unsigned int width, unsigned int height);\n\n}} // namespace\n\n#endif //MANGOHUD_GL_IMGUI_HUD_H\n"
  },
  {
    "path": "src/gl/gl_renderer.cpp",
    "content": "// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline\n// - Desktop GL: 2.x 3.x 4.x\n// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!\n//  [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.\n\n// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.\n// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.\n// https://github.com/ocornut/imgui\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.\n//  2020-01-07: OpenGL: Added support for glbindings OpenGL loader.\n//  2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.\n//  2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.\n//  2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.\n//  2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.\n//  2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.\n//  2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.\n//  2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.\n//  2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).\n//  2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.\n//  2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.\n//  2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).\n//  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.\n//  2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.\n//  2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.\n//  2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to \"#version 300 ES\".\n//  2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.\n//  2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.\n//  2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.\n//  2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.\n//  2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.\n//  2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.\n//  2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. \"#version 150\".\n//  2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.\n//  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.\n//  2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.\n//  2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.\n//  2017-05-01: OpenGL: Fixed save and restore of current blend func state.\n//  2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.\n//  2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.\n//  2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)\n\n//----------------------------------------\n// OpenGL    GLSL      GLSL\n// version   version   string\n//----------------------------------------\n//  2.0       110       \"#version 110\"\n//  2.1       120       \"#version 120\"\n//  3.0       130       \"#version 130\"\n//  3.1       140       \"#version 140\"\n//  3.2       150       \"#version 150\"\n//  3.3       330       \"#version 330 core\"\n//  4.0       400       \"#version 400 core\"\n//  4.1       410       \"#version 410 core\"\n//  4.2       420       \"#version 410 core\"\n//  4.3       430       \"#version 430 core\"\n//  ES 2.0    100       \"#version 100\"      = WebGL 1.0\n//  ES 3.0    300       \"#version 300 es\"   = WebGL 2.0\n//----------------------------------------\n\n#include <spdlog/spdlog.h>\n#include <imgui.h>\n#include \"gl_renderer.h\"\n#include <stdio.h>\n#include <stdint.h>     // intptr_t\n#include <sstream>\n\n#include <spdlog/spdlog.h>\n#include <glad/glad.h>\n\n#include \"overlay.h\"\n\nnamespace MangoHud { namespace GL {\n\nextern overlay_params params;\n\n// OpenGL Data\nstatic gl_context* g_current_ctx;\nstatic GLuint      g_GlVersion = 0;                // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries.\nstatic char        g_GlslVersionString[32] = \"\";   // Specified by user or detected based on compile time GL settings.\nstatic bool        g_IsGLES = false;\n\n// Functions\nvoid ImGui_ImplOpenGL3_DestroyFontsTexture(gl_context *ctx)\n{\n    if (ctx->FontTexture)\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        glDeleteTextures(1, &ctx->FontTexture);\n        io.Fonts->SetTexID(0);\n        ctx->FontTexture = 0;\n    }\n}\n\nbool ImGui_ImplOpenGL3_CreateFontsTexture(gl_context *ctx)\n{\n    // Build texture atlas\n    ImGuiIO& io = ImGui::GetIO();\n    unsigned char* pixels;\n    int width, height;\n    io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);\n\n    // OpenGL specification defaults, overwritten by glGet but initialized just in case.\n    GLint last_texture = 0;\n    GLint last_unpack_buffer = 0;\n    GLint last_unpack_row_length = 0;\n    GLint last_unpack_skip_pixels = 0;\n    GLint last_unpack_skip_rows = 0;\n    GLint last_unpack_alignment = 4;\n\n\n    // Upload texture to graphics system\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n    glGenTextures(1, &ctx->FontTexture);\n    glBindTexture(GL_TEXTURE_2D, ctx->FontTexture);\n    if ((g_IsGLES && g_GlVersion >= 300) || (!g_IsGLES && g_GlVersion >= 210))\n    {\n        glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &last_unpack_buffer);\n        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);\n\n        glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length);\n        glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &last_unpack_skip_pixels);\n        glGetIntegerv(GL_UNPACK_SKIP_ROWS, &last_unpack_skip_rows);\n        // Values here are OpenGL specification default\n        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);\n        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);\n        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);\n    }\n    glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment);\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // OpenGL specification default\n\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, pixels);\n\n    // Store our identifier\n    io.Fonts->SetTexID((ImTextureID)(intptr_t)ctx->FontTexture);\n\n    // Restore state\n    glBindTexture(GL_TEXTURE_2D, last_texture);\n    if ((g_IsGLES && g_GlVersion >= 300) || (!g_IsGLES && g_GlVersion >= 210))\n    {\n        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, last_unpack_buffer);\n        glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length);\n        glPixelStorei(GL_UNPACK_SKIP_PIXELS, last_unpack_skip_pixels);\n        glPixelStorei(GL_UNPACK_SKIP_ROWS, last_unpack_skip_rows);\n    }\n    glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment);\n\n    return true;\n}\n\n// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.\nstatic bool CheckShader(GLuint handle, const char* desc)\n{\n    GLint status = 0, log_length = 0;\n    glGetShaderiv(handle, GL_COMPILE_STATUS, &status);\n    glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n    if ((GLboolean)status == GL_FALSE)\n        SPDLOG_ERROR(\"ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile {}!\", desc);\n    if (log_length > 1)\n    {\n        ImVector<char> buf;\n        buf.resize((int)(log_length + 1));\n        glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n        SPDLOG_ERROR(\"{}\", buf.begin());\n    }\n    return (GLboolean)status == GL_TRUE;\n}\n\n// If you get an error please report on GitHub. You may try different GL context version or GLSL version.\nstatic bool CheckProgram(GLuint handle, const char* desc)\n{\n    GLint status = 0, log_length = 0;\n    glGetProgramiv(handle, GL_LINK_STATUS, &status);\n    glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n    if ((GLboolean)status == GL_FALSE)\n        SPDLOG_ERROR(\"ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link {}! (with GLSL '{}')\", desc, g_GlslVersionString);\n    if (log_length > 1)\n    {\n        ImVector<char> buf;\n        buf.resize((int)(log_length + 1));\n        glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n        SPDLOG_ERROR(\"{}\", buf.begin());\n    }\n    return (GLboolean)status == GL_TRUE;\n}\n\nstatic bool    ImGui_ImplOpenGL3_CreateDeviceObjects(gl_context *ctx)\n{\n    // Parse GLSL version string\n    int glsl_version = 120;\n    sscanf(g_GlslVersionString, \"#version %d\", &glsl_version);\n\n    const GLchar* vertex_shader_glsl_120 =\n        \"uniform mat4 ProjMtx;\\n\"\n        \"attribute vec2 Position;\\n\"\n        \"attribute vec2 UV;\\n\"\n        \"attribute vec4 Color;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_130 =\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 UV;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_300_es =\n        \"precision mediump float;\\n\"\n        \"layout (location = 0) in vec2 Position;\\n\"\n        \"layout (location = 1) in vec2 UV;\\n\"\n        \"layout (location = 2) in vec4 Color;\\n\"\n        \"uniform mat4 ProjMtx;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        \"}\\n\";\n\n    const GLchar* vertex_shader_glsl_410_core =\n        \"layout (location = 0) in vec2 Position;\\n\"\n        \"layout (location = 1) in vec2 UV;\\n\"\n        \"layout (location = 2) in vec4 Color;\\n\"\n        \"uniform mat4 ProjMtx;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Frag_UV = UV;\\n\"\n        \"    Frag_Color = Color;\\n\"\n        \"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n        //\"    gl_Position = ProjMtx * vec4(Position.xy,0,1) * vec4(1.0, -1.0, 1, 1);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_120 =\n        \"#ifdef GL_ES\\n\"\n        \"    precision mediump float;\\n\"\n        \"#endif\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    gl_FragColor = Frag_Color * vec4(1, 1, 1, texture2D(Texture, Frag_UV.st).r);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_130 =\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_300_es =\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"layout (location = 0) out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\\n\"\n        \"}\\n\";\n\n    const GLchar* fragment_shader_glsl_410_core =\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"layout (location = 0) out vec4 Out_Color;\\n\"\n        \"void main()\\n\"\n        \"{\\n\"\n        \"    Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\\n\"\n        \"}\\n\";\n\n    SPDLOG_DEBUG(\"glsl_version: {}\", glsl_version);\n\n    // Select shaders matching our GLSL versions\n    const GLchar* vertex_shader = NULL;\n    const GLchar* fragment_shader = NULL;\n    if (glsl_version < 130)\n    {\n        vertex_shader = vertex_shader_glsl_120;\n        fragment_shader = fragment_shader_glsl_120;\n    }\n    else if (glsl_version >= 410)\n    {\n        vertex_shader = vertex_shader_glsl_410_core;\n        fragment_shader = fragment_shader_glsl_410_core;\n    }\n    else if (glsl_version == 300)\n    {\n        vertex_shader = vertex_shader_glsl_300_es;\n        fragment_shader = fragment_shader_glsl_300_es;\n    }\n    else\n    {\n        vertex_shader = vertex_shader_glsl_130;\n        fragment_shader = fragment_shader_glsl_130;\n    }\n\n    std::stringstream ss;\n    ss << g_GlslVersionString << vertex_shader;\n    std::string shader = ss.str();\n\n    // Create shaders\n    //const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };\n    const GLchar* vertex_shader_with_version[1] = { shader.c_str() };\n    ctx->VertHandle = glCreateShader(GL_VERTEX_SHADER);\n    glShaderSource(ctx->VertHandle, 1, vertex_shader_with_version, NULL);\n    glCompileShader(ctx->VertHandle);\n    CheckShader(ctx->VertHandle, \"vertex shader\");\n\n    ss.str(\"\"); ss.clear();\n    ss << g_GlslVersionString << fragment_shader;\n    shader = ss.str();\n\n    const GLchar* fragment_shader_with_version[1] = { shader.c_str() };\n    ctx->FragHandle = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(ctx->FragHandle, 1, fragment_shader_with_version, NULL);\n    glCompileShader(ctx->FragHandle);\n    CheckShader(ctx->FragHandle, \"fragment shader\");\n\n    ctx->ShaderHandle = glCreateProgram();\n    glAttachShader(ctx->ShaderHandle, ctx->VertHandle);\n    glAttachShader(ctx->ShaderHandle, ctx->FragHandle);\n    glLinkProgram(ctx->ShaderHandle);\n    CheckProgram(ctx->ShaderHandle, \"shader program\");\n    SPDLOG_DEBUG(\"g_ShaderHandle {}\", ctx->ShaderHandle);\n\n    ctx->AttribLocationTex = glGetUniformLocation(ctx->ShaderHandle, \"Texture\");\n    ctx->AttribLocationProjMtx = glGetUniformLocation(ctx->ShaderHandle, \"ProjMtx\");\n    ctx->AttribLocationVtxPos = glGetAttribLocation(ctx->ShaderHandle, \"Position\");\n    ctx->AttribLocationVtxUV = glGetAttribLocation(ctx->ShaderHandle, \"UV\");\n    ctx->AttribLocationVtxColor = glGetAttribLocation(ctx->ShaderHandle, \"Color\");\n    SPDLOG_DEBUG(\"g_AttribLocationTex {}, g_AttribLocationProjMtx {}, g_AttribLocationVtxPos {}, g_AttribLocationVtxUV {}, g_AttribLocationVtxColor {}\",\n                 ctx->AttribLocationTex, ctx->AttribLocationProjMtx, ctx->AttribLocationVtxPos, ctx->AttribLocationVtxUV, ctx->AttribLocationVtxColor);\n\n    // Create buffers\n    glGenBuffers(1, &ctx->VboHandle);\n    glGenBuffers(1, &ctx->ElementsHandle);\n\n    ImGui_ImplOpenGL3_CreateFontsTexture(ctx);\n\n    return true;\n}\n\nstatic void    ImGui_ImplOpenGL3_DestroyDeviceObjects(gl_context *ctx)\n{\n    if (ctx->VboHandle)        { glDeleteBuffers(1, &ctx->VboHandle); ctx->VboHandle = 0; }\n    if (ctx->ElementsHandle)   { glDeleteBuffers(1, &ctx->ElementsHandle); ctx->ElementsHandle = 0; }\n    if (ctx->ShaderHandle && ctx->VertHandle) { glDetachShader(ctx->ShaderHandle, ctx->VertHandle); }\n    if (ctx->ShaderHandle && ctx->FragHandle) { glDetachShader(ctx->ShaderHandle, ctx->FragHandle); }\n    if (ctx->VertHandle)       { glDeleteShader(ctx->VertHandle); ctx->VertHandle = 0; }\n    if (ctx->FragHandle)       { glDeleteShader(ctx->FragHandle); ctx->FragHandle = 0; }\n    if (ctx->ShaderHandle)     { glDeleteProgram(ctx->ShaderHandle); ctx->ShaderHandle = 0; }\n\n    ImGui_ImplOpenGL3_DestroyFontsTexture(ctx);\n}\n\nvoid GetOpenGLVersion(int& major, int& minor, bool& isGLES)\n{\n    //glGetIntegerv(GL_MAJOR_VERSION, &major);\n    //glGetIntegerv(GL_MINOR_VERSION, &minor);\n\n    const char* version;\n    const char* prefixes[] = {\n        \"OpenGL ES-CM \",\n        \"OpenGL ES-CL \",\n        \"OpenGL ES \",\n        nullptr\n    };\n\n    version = (const char*) glGetString(GL_VERSION);\n    if (!version)\n    {\n        SPDLOG_ERROR(\"couldn't get GL version string\");\n        return;\n    }\n\n    //if (glGetError() == 0x500)\n    {\n        for (int 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                isGLES = true;\n                break;\n            }\n        }\n\n        sscanf(version, \"%d.%d\", &major, &minor);\n    }\n}\n\nbool    ImGui_ImplOpenGL3_Init(gl_context* ctx, const char* glsl_version)\n{\n    if (ctx != g_current_ctx)\n    {\n        //SPDLOG_TRACE(\"switched to ctx {}\", (void*)ctx);\n        g_current_ctx = ctx;\n    }\n    GLint major = 0, minor = 0;\n    GetOpenGLVersion(major, minor, g_IsGLES);\n\n    SPDLOG_DEBUG(\"GL version: {}.{} {}\", major, minor, g_IsGLES ? \"ES\" : \"\");\n\n    if (!g_IsGLES) {\n        // Not GL ES\n        glsl_version = \"#version 120\";\n        g_GlVersion = major * 100 + minor * 10;\n        if (major >= 4 && minor >= 1)\n            glsl_version = \"#version 410\";\n        else if (major > 3 || (major == 3 && minor >= 2))\n            glsl_version = \"#version 150\";\n        else if (major == 3)\n            glsl_version = \"#version 130\";\n        else if (major < 2)\n            glsl_version = \"#version 100\";\n    } else {\n        if (major >= 3)\n            g_GlVersion = major * 100 + minor * 10; // GLES >= 3\n        else\n            g_GlVersion = 200; // GLES 2\n\n        // Store GLSL version string so we can refer to it later in case we recreate shaders.\n        // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.\n        if (g_GlVersion == 200)\n            glsl_version = \"#version 100\";\n        else if (g_GlVersion >= 300)\n            glsl_version = \"#version 300 es\";\n        else\n            glsl_version = \"#version 120\";\n    }\n\n    // Setup back-end capabilities flags\n    ImGuiIO& io = ImGui::GetIO();\n    io.BackendRendererName = \"mangohud_opengl3\";\n    //#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET\n    if (g_GlVersion >= 320) // GL/GLES 3.2+\n        io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n\n    // Store GLSL version string so we can refer to it later in case we recreate shaders.\n    // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.\n    if (glsl_version == NULL)\n        glsl_version = \"#version 120\";\n\n    IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));\n    strcpy(g_GlslVersionString, glsl_version);\n    strcat(g_GlslVersionString, \"\\n\");\n\n    // Make a dummy GL call (we don't actually need the result)\n    // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.\n    // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.\n    GLint current_texture;\n    glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);\n\n    return true;\n}\n\nvoid    ImGui_ImplOpenGL3_Shutdown(gl_context* ctx)\n{\n    ImGui_ImplOpenGL3_DestroyDeviceObjects(ctx);\n    if (ctx == g_current_ctx)\n    {\n        //SPDLOG_TRACE(\"current_ctx {} destroyed\", (void*)ctx);\n        g_current_ctx = nullptr;\n    }\n}\n\nvoid    ImGui_ImplOpenGL3_NewFrame(gl_context* ctx)\n{\n    if (ctx != g_current_ctx)\n    {\n        ImGuiIO& io = ImGui::GetIO();\n        //SPDLOG_TRACE(\"switched to ctx {}\", (void*)ctx);\n        g_current_ctx = ctx;\n        io.Fonts->SetTexID((ImTextureID)(intptr_t)ctx->FontTexture);\n    }\n    //SPDLOG_DEBUG(\"g_ShaderHandle {}\", g_current_ctx->ShaderHandle);\n    if (!ctx->ShaderHandle)\n    {\n        SPDLOG_TRACE(\"No shader object, creating device objects\");\n        ImGui_ImplOpenGL3_CreateDeviceObjects(ctx);\n    }\n}\n\nstatic void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)\n{\n    // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill\n    if (params.gl_bind_framebuffer >= 0 && (g_IsGLES || g_GlVersion >= 300))\n        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, params.gl_bind_framebuffer);\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glDisable(GL_STENCIL_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glDisable(GL_FRAMEBUFFER_SRGB);\n    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);\n\n    if (!g_IsGLES)\n    {\n        //#ifdef GL_POLYGON_MODE\n        if (g_GlVersion >= 200)\n            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n        if (g_GlVersion >= 310)\n            glDisable(GL_PRIMITIVE_RESTART);\n    }\n\n    bool clip_origin_lower_left = true;\n    GLenum last_clip_origin = 0;\n    if (!g_IsGLES && /*g_GlVersion >= 450*/ (glad_glClipControl || glad_glClipControlEXT)) {\n        glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)\n        if (last_clip_origin == GL_UPPER_LEFT)\n            clip_origin_lower_left = false;\n    }\n\n    // Setup viewport, orthographic projection matrix\n    // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.\n    glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);\n    float L = draw_data->DisplayPos.x;\n    float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;\n    float T = draw_data->DisplayPos.y;\n    float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;\n    if (!params.gl_dont_flip && !clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left\n    const float ortho_projection[4][4] =\n    {\n        { 2.0f/(R-L),   0.0f,         0.0f,   0.0f },\n        { 0.0f,         2.0f/(T-B),   0.0f,   0.0f },\n        { 0.0f,         0.0f,        -1.0f,   0.0f },\n        { (R+L)/(L-R),  (T+B)/(B-T),  0.0f,   1.0f },\n    };\n    glUseProgram(g_current_ctx->ShaderHandle);\n    glUniform1i(g_current_ctx->AttribLocationTex, 0);\n    glUniformMatrix4fv(g_current_ctx->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);\n\n    if (g_GlVersion >= 330)\n        glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.\n\n    (void)vertex_array_object;\n    //#ifndef IMGUI_IMPL_OPENGL_ES2\n    if (g_GlVersion >= 300)\n        glBindVertexArray(vertex_array_object);\n\n    // Bind vertex/index buffers and setup attributes for ImDrawVert\n    glBindBuffer(GL_ARRAY_BUFFER, g_current_ctx->VboHandle);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_current_ctx->ElementsHandle);\n    glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxPos);\n    glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxUV);\n    glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxColor);\n    glVertexAttribPointer(g_current_ctx->AttribLocationVtxPos,   2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));\n    glVertexAttribPointer(g_current_ctx->AttribLocationVtxUV,    2, GL_FLOAT,         GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));\n    glVertexAttribPointer(g_current_ctx->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));\n}\n\n// OpenGL3 Render function.\n// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)\n// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.\nvoid    ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)\n{\n    // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)\n    int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);\n    int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);\n    if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0)\n        return;\n\n    // Backup GL state\n    GLint last_fb = -1;\n    if (params.gl_bind_framebuffer >= 0 && (g_IsGLES || g_GlVersion >= 300))\n        glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fb);\n    GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);\n    glActiveTexture(GL_TEXTURE0);\n    GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);\n    GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n\n    // GL_SAMPLER_BINDING\n    GLint last_sampler;\n    if (!g_IsGLES && g_GlVersion >= 330)\n        glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);\n\n    GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);\n\n//#ifndef IMGUI_IMPL_OPENGL_ES2\n    GLint last_vertex_array_object;\n    if (g_GlVersion >= 300)\n        glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);\n\n    GLint last_polygon_mode[2];\n    if (!g_IsGLES && g_GlVersion >= 200)\n        glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);\n\n    GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);\n    GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);\n    GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);\n    GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);\n    GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);\n    GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);\n    GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);\n    GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);\n    GLboolean last_enable_blend = glIsEnabled(GL_BLEND);\n    GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);\n    GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);\n    GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);\n    GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);\n    // Disable and store SRGB state.\n    GLboolean last_srgb_enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB);\n    GLboolean last_enable_primitive_restart = (!g_IsGLES && g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;\n\n    // Setup desired GL state\n    // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)\n    // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.\n    GLuint vertex_array_object = 0;\n    if (g_GlVersion >= 300)\n        glGenVertexArrays(1, &vertex_array_object);\n\n    ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n\n    // Will project scissor/clipping rectangles into framebuffer space\n    ImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports\n    ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)\n\n    //SPDLOG_DEBUG(\"draw_data->CmdListsCount {}\", draw_data->CmdListsCount);\n    // Render command lists\n    for (int n = 0; n < draw_data->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = draw_data->CmdLists[n];\n\n        // Upload vertex/index buffers\n        glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);\n\n        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n        {\n            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n            if (pcmd->UserCallback != NULL)\n            {\n                // User callback, registered via ImDrawList::AddCallback()\n                // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)\n                if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)\n                    ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n                else\n                    pcmd->UserCallback(cmd_list, pcmd);\n            }\n            else\n            {\n                // Project scissor/clipping rectangles into framebuffer space\n                ImVec4 clip_rect;\n                clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;\n                clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;\n                clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;\n                clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;\n\n                if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)\n                {\n                    // Apply scissor/clipping rectangle\n                    if (!params.gl_dont_flip)\n                        glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));\n                    else\n                        glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w);\n\n                    // Bind texture, Draw\n                    glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);\n                    //#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET\n                    if (g_GlVersion >= 320) // OGL and OGL ES\n                        glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);\n                    else\n                        glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));\n                }\n            }\n        }\n    }\n\n    // Destroy the temporary VAO\n    if (g_GlVersion >= 300)\n        glDeleteVertexArrays(1, &vertex_array_object);\n\n    // Restore modified GL state\n    glUseProgram(last_program);\n    glBindTexture(GL_TEXTURE_2D, last_texture);\n\n    if (!g_IsGLES && g_GlVersion >= 330)\n        glBindSampler(0, last_sampler);\n\n    glActiveTexture(last_active_texture);\n\n    if (g_GlVersion >= 300)\n        glBindVertexArray(last_vertex_array_object);\n\n    glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);\n    glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);\n    glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);\n    if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);\n    if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);\n    if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);\n    if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);\n    if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);\n    if (!g_IsGLES && g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); }\n\n    if (!g_IsGLES && g_GlVersion >= 200)\n        glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);\n\n    glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);\n    glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);\n\n    if (last_srgb_enabled)\n        glEnable(GL_FRAMEBUFFER_SRGB);\n    if (last_fb >= 0)\n        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, last_fb);\n}\n\n}} // namespace\n"
  },
  {
    "path": "src/gl/gl_renderer.h",
    "content": "// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline\n// - Desktop GL: 2.x 3.x 4.x\n// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!\n//  [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.\n\n// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.\n// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.\n// https://github.com/ocornut/imgui\n\n// About Desktop OpenGL function loaders:\n//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.\n//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).\n//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.\n\n// About GLSL version:\n//  The 'glsl_version' initialization parameter should be NULL (default) or a \"#version XXX\" string.\n//  On computer platform the GLSL version default to \"#version 130\". On OpenGL ES 3 platform it defaults to \"#version 300 es\"\n//  Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.\n\n#pragma once\n#ifndef MANGOHUD_IMGUI_IMPL_OPENGL3_H\n#define MANGOHUD_IMGUI_IMPL_OPENGL3_H\n\n#include <glad/glad.h>\n\nnamespace MangoHud { namespace GL {\n\nstruct gl_context\n{\n    void *ctx;\n    GLuint FontTexture = 0;\n    GLuint ShaderHandle = 0, VertHandle = 0, FragHandle = 0;\n    int AttribLocationTex = 0, AttribLocationProjMtx = 0;                                // Uniforms location\n    int AttribLocationVtxPos = 0, AttribLocationVtxUV = 0, AttribLocationVtxColor = 0; // Vertex attributes location\n    unsigned int VboHandle = 0, ElementsHandle = 0;\n    bool swap_interval_set = false;\n};\n\n\nvoid GetOpenGLVersion(int& major, int& minor, bool& isGLES);\n\n// Backend API\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_Init(gl_context* ctx, const char* glsl_version = nullptr);\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_Shutdown(gl_context* ctx);\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_NewFrame(gl_context* ctx);\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyFontsTexture(gl_context* ctx);\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateFontsTexture(gl_context* ctx);\n\n// (Optional) Called by Init/NewFrame/Shutdown\n//IMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateFontsTexture();\n//IMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyFontsTexture();\n//IMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateDeviceObjects();\n//IMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyDeviceObjects();\n\n}}\n\n#endif //MANGOHUD_IMGUI_IMPL_OPENGL3_H\n"
  },
  {
    "path": "src/gl/glad.c",
    "content": "/*\n\n    OpenGL, OpenGL ES loader generated by glad 0.1.33 on Thu Apr  9 12:37:38 2020.\n\n    Language/Generator: C/C++\n    Specification: gl\n    APIs: gl=4.6, gles2=3.2\n    Profile: compatibility\n    Extensions:\n        GL_ARB_clip_control,\n        GL_EXT_clip_control\n    Loader: True\n    Local files: False\n    Omit khrplatform: False\n    Reproducible: False\n\n    Commandline:\n        --profile=\"compatibility\" --api=\"gl=4.6,gles2=3.2\" --generator=\"c\" --spec=\"gl\" --extensions=\"GL_ARB_clip_control,GL_EXT_clip_control\"\n    Online:\n        https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_clip_control&extensions=GL_EXT_clip_control\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;\nint GLAD_GL_VERSION_4_0 = 0;\nint GLAD_GL_VERSION_4_1 = 0;\nint GLAD_GL_VERSION_4_2 = 0;\nint GLAD_GL_VERSION_4_3 = 0;\nint GLAD_GL_VERSION_4_4 = 0;\nint GLAD_GL_VERSION_4_5 = 0;\nint GLAD_GL_VERSION_4_6 = 0;\nint GLAD_GL_ES_VERSION_2_0 = 0;\nint GLAD_GL_ES_VERSION_3_0 = 0;\nint GLAD_GL_ES_VERSION_3_1 = 0;\nint GLAD_GL_ES_VERSION_3_2 = 0;\nPFNGLACCUMPROC glad_glAccum = NULL;\nPFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;\nPFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;\nPFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL;\nPFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL;\nPFNGLARRAYELEMENTPROC glad_glArrayElement = NULL;\nPFNGLATTACHSHADERPROC glad_glAttachShader = NULL;\nPFNGLBEGINPROC glad_glBegin = NULL;\nPFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;\nPFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;\nPFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;\nPFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;\nPFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;\nPFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;\nPFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;\nPFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;\nPFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL;\nPFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL;\nPFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;\nPFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;\nPFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;\nPFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;\nPFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL;\nPFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;\nPFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;\nPFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;\nPFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;\nPFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;\nPFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL;\nPFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;\nPFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;\nPFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;\nPFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;\nPFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL;\nPFNGLBITMAPPROC glad_glBitmap = NULL;\nPFNGLBLENDBARRIERPROC glad_glBlendBarrier = NULL;\nPFNGLBLENDCOLORPROC glad_glBlendColor = NULL;\nPFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;\nPFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;\nPFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;\nPFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;\nPFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;\nPFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;\nPFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;\nPFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;\nPFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;\nPFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL;\nPFNGLBUFFERDATAPROC glad_glBufferData = NULL;\nPFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;\nPFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;\nPFNGLCALLLISTPROC glad_glCallList = NULL;\nPFNGLCALLLISTSPROC glad_glCallLists = NULL;\nPFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;\nPFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL;\nPFNGLCLAMPCOLORPROC glad_glClampColor = NULL;\nPFNGLCLEARPROC glad_glClear = NULL;\nPFNGLCLEARACCUMPROC glad_glClearAccum = NULL;\nPFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;\nPFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = 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;\nPFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;\nPFNGLCLEARINDEXPROC glad_glClearIndex = NULL;\nPFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL;\nPFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL;\nPFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL;\nPFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL;\nPFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL;\nPFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL;\nPFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;\nPFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;\nPFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;\nPFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL;\nPFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;\nPFNGLCLIPCONTROLPROC glad_glClipControl = NULL;\nPFNGLCLIPPLANEPROC glad_glClipPlane = NULL;\nPFNGLCOLOR3BPROC glad_glColor3b = NULL;\nPFNGLCOLOR3BVPROC glad_glColor3bv = NULL;\nPFNGLCOLOR3DPROC glad_glColor3d = NULL;\nPFNGLCOLOR3DVPROC glad_glColor3dv = NULL;\nPFNGLCOLOR3FPROC glad_glColor3f = NULL;\nPFNGLCOLOR3FVPROC glad_glColor3fv = NULL;\nPFNGLCOLOR3IPROC glad_glColor3i = NULL;\nPFNGLCOLOR3IVPROC glad_glColor3iv = NULL;\nPFNGLCOLOR3SPROC glad_glColor3s = NULL;\nPFNGLCOLOR3SVPROC glad_glColor3sv = NULL;\nPFNGLCOLOR3UBPROC glad_glColor3ub = NULL;\nPFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL;\nPFNGLCOLOR3UIPROC glad_glColor3ui = NULL;\nPFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL;\nPFNGLCOLOR3USPROC glad_glColor3us = NULL;\nPFNGLCOLOR3USVPROC glad_glColor3usv = NULL;\nPFNGLCOLOR4BPROC glad_glColor4b = NULL;\nPFNGLCOLOR4BVPROC glad_glColor4bv = NULL;\nPFNGLCOLOR4DPROC glad_glColor4d = NULL;\nPFNGLCOLOR4DVPROC glad_glColor4dv = NULL;\nPFNGLCOLOR4FPROC glad_glColor4f = NULL;\nPFNGLCOLOR4FVPROC glad_glColor4fv = NULL;\nPFNGLCOLOR4IPROC glad_glColor4i = NULL;\nPFNGLCOLOR4IVPROC glad_glColor4iv = NULL;\nPFNGLCOLOR4SPROC glad_glColor4s = NULL;\nPFNGLCOLOR4SVPROC glad_glColor4sv = NULL;\nPFNGLCOLOR4UBPROC glad_glColor4ub = NULL;\nPFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL;\nPFNGLCOLOR4UIPROC glad_glColor4ui = NULL;\nPFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL;\nPFNGLCOLOR4USPROC glad_glColor4us = NULL;\nPFNGLCOLOR4USVPROC glad_glColor4usv = NULL;\nPFNGLCOLORMASKPROC glad_glColorMask = NULL;\nPFNGLCOLORMASKIPROC glad_glColorMaski = NULL;\nPFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL;\nPFNGLCOLORP3UIPROC glad_glColorP3ui = NULL;\nPFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL;\nPFNGLCOLORP4UIPROC glad_glColorP4ui = NULL;\nPFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL;\nPFNGLCOLORPOINTERPROC glad_glColorPointer = 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;\nPFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL;\nPFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL;\nPFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL;\nPFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;\nPFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;\nPFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL;\nPFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL;\nPFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;\nPFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;\nPFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;\nPFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL;\nPFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL;\nPFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL;\nPFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL;\nPFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL;\nPFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;\nPFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL;\nPFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL;\nPFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL;\nPFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL;\nPFNGLCREATESHADERPROC glad_glCreateShader = NULL;\nPFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;\nPFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL;\nPFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL;\nPFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL;\nPFNGLCULLFACEPROC glad_glCullFace = NULL;\nPFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;\nPFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;\nPFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;\nPFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;\nPFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;\nPFNGLDELETELISTSPROC glad_glDeleteLists = NULL;\nPFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;\nPFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = 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;\nPFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;\nPFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;\nPFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;\nPFNGLDEPTHMASKPROC glad_glDepthMask = NULL;\nPFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;\nPFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;\nPFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;\nPFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;\nPFNGLDETACHSHADERPROC glad_glDetachShader = NULL;\nPFNGLDISABLEPROC glad_glDisable = NULL;\nPFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL;\nPFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL;\nPFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;\nPFNGLDISABLEIPROC glad_glDisablei = NULL;\nPFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;\nPFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;\nPFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;\nPFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;\nPFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;\nPFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;\nPFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;\nPFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;\nPFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;\nPFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;\nPFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;\nPFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;\nPFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;\nPFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;\nPFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;\nPFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL;\nPFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;\nPFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;\nPFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL;\nPFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL;\nPFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL;\nPFNGLENABLEPROC glad_glEnable = NULL;\nPFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL;\nPFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL;\nPFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;\nPFNGLENABLEIPROC glad_glEnablei = NULL;\nPFNGLENDPROC glad_glEnd = NULL;\nPFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;\nPFNGLENDLISTPROC glad_glEndList = NULL;\nPFNGLENDQUERYPROC glad_glEndQuery = NULL;\nPFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;\nPFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;\nPFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL;\nPFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL;\nPFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL;\nPFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL;\nPFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL;\nPFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL;\nPFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL;\nPFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL;\nPFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL;\nPFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL;\nPFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL;\nPFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL;\nPFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL;\nPFNGLFENCESYNCPROC glad_glFenceSync = NULL;\nPFNGLFINISHPROC glad_glFinish = NULL;\nPFNGLFLUSHPROC glad_glFlush = NULL;\nPFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;\nPFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL;\nPFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL;\nPFNGLFOGCOORDDPROC glad_glFogCoordd = NULL;\nPFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL;\nPFNGLFOGCOORDFPROC glad_glFogCoordf = NULL;\nPFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL;\nPFNGLFOGFPROC glad_glFogf = NULL;\nPFNGLFOGFVPROC glad_glFogfv = NULL;\nPFNGLFOGIPROC glad_glFogi = NULL;\nPFNGLFOGIVPROC glad_glFogiv = NULL;\nPFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = 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;\nPFNGLFRUSTUMPROC glad_glFrustum = NULL;\nPFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;\nPFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;\nPFNGLGENLISTSPROC glad_glGenLists = NULL;\nPFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;\nPFNGLGENQUERIESPROC glad_glGenQueries = NULL;\nPFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;\nPFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;\nPFNGLGENTEXTURESPROC glad_glGenTextures = NULL;\nPFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;\nPFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;\nPFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;\nPFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL;\nPFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;\nPFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;\nPFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;\nPFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;\nPFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = 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;\nPFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL;\nPFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;\nPFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL;\nPFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL;\nPFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;\nPFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;\nPFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;\nPFNGLGETERRORPROC glad_glGetError = NULL;\nPFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;\nPFNGLGETFLOATVPROC glad_glGetFloatv = NULL;\nPFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;\nPFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;\nPFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;\nPFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;\nPFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus = NULL;\nPFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;\nPFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;\nPFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;\nPFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;\nPFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;\nPFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;\nPFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL;\nPFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL;\nPFNGLGETMAPDVPROC glad_glGetMapdv = NULL;\nPFNGLGETMAPFVPROC glad_glGetMapfv = NULL;\nPFNGLGETMAPIVPROC glad_glGetMapiv = NULL;\nPFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL;\nPFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL;\nPFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;\nPFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL;\nPFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL;\nPFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL;\nPFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL;\nPFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL;\nPFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL;\nPFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL;\nPFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;\nPFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;\nPFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL;\nPFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL;\nPFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL;\nPFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;\nPFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL;\nPFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;\nPFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;\nPFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;\nPFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;\nPFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;\nPFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;\nPFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;\nPFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;\nPFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;\nPFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;\nPFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;\nPFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;\nPFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL;\nPFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL;\nPFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL;\nPFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL;\nPFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = 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;\nPFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;\nPFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;\nPFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;\nPFNGLGETSTRINGPROC glad_glGetString = NULL;\nPFNGLGETSTRINGIPROC glad_glGetStringi = NULL;\nPFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;\nPFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;\nPFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;\nPFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL;\nPFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL;\nPFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL;\nPFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL;\nPFNGLGETTEXGENIVPROC glad_glGetTexGeniv = 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;\nPFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL;\nPFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL;\nPFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL;\nPFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL;\nPFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL;\nPFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL;\nPFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL;\nPFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL;\nPFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;\nPFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL;\nPFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL;\nPFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL;\nPFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;\nPFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;\nPFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;\nPFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;\nPFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;\nPFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;\nPFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;\nPFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;\nPFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL;\nPFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL;\nPFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL;\nPFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;\nPFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;\nPFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;\nPFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;\nPFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;\nPFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;\nPFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;\nPFNGLGETNCOLORTABLEPROC glad_glGetnColorTable = NULL;\nPFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage = NULL;\nPFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter = NULL;\nPFNGLGETNHISTOGRAMPROC glad_glGetnHistogram = NULL;\nPFNGLGETNMAPDVPROC glad_glGetnMapdv = NULL;\nPFNGLGETNMAPFVPROC glad_glGetnMapfv = NULL;\nPFNGLGETNMAPIVPROC glad_glGetnMapiv = NULL;\nPFNGLGETNMINMAXPROC glad_glGetnMinmax = NULL;\nPFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv = NULL;\nPFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv = NULL;\nPFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv = NULL;\nPFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple = NULL;\nPFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter = NULL;\nPFNGLGETNTEXIMAGEPROC glad_glGetnTexImage = NULL;\nPFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv = NULL;\nPFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL;\nPFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL;\nPFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL;\nPFNGLHINTPROC glad_glHint = NULL;\nPFNGLINDEXMASKPROC glad_glIndexMask = NULL;\nPFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL;\nPFNGLINDEXDPROC glad_glIndexd = NULL;\nPFNGLINDEXDVPROC glad_glIndexdv = NULL;\nPFNGLINDEXFPROC glad_glIndexf = NULL;\nPFNGLINDEXFVPROC glad_glIndexfv = NULL;\nPFNGLINDEXIPROC glad_glIndexi = NULL;\nPFNGLINDEXIVPROC glad_glIndexiv = NULL;\nPFNGLINDEXSPROC glad_glIndexs = NULL;\nPFNGLINDEXSVPROC glad_glIndexsv = NULL;\nPFNGLINDEXUBPROC glad_glIndexub = NULL;\nPFNGLINDEXUBVPROC glad_glIndexubv = NULL;\nPFNGLINITNAMESPROC glad_glInitNames = NULL;\nPFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL;\nPFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;\nPFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;\nPFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;\nPFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL;\nPFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL;\nPFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;\nPFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;\nPFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;\nPFNGLISBUFFERPROC glad_glIsBuffer = NULL;\nPFNGLISENABLEDPROC glad_glIsEnabled = NULL;\nPFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;\nPFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;\nPFNGLISLISTPROC glad_glIsList = NULL;\nPFNGLISPROGRAMPROC glad_glIsProgram = NULL;\nPFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = 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;\nPFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;\nPFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;\nPFNGLLIGHTMODELFPROC glad_glLightModelf = NULL;\nPFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL;\nPFNGLLIGHTMODELIPROC glad_glLightModeli = NULL;\nPFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL;\nPFNGLLIGHTFPROC glad_glLightf = NULL;\nPFNGLLIGHTFVPROC glad_glLightfv = NULL;\nPFNGLLIGHTIPROC glad_glLighti = NULL;\nPFNGLLIGHTIVPROC glad_glLightiv = NULL;\nPFNGLLINESTIPPLEPROC glad_glLineStipple = NULL;\nPFNGLLINEWIDTHPROC glad_glLineWidth = NULL;\nPFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;\nPFNGLLISTBASEPROC glad_glListBase = NULL;\nPFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL;\nPFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL;\nPFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL;\nPFNGLLOADNAMEPROC glad_glLoadName = NULL;\nPFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL;\nPFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL;\nPFNGLLOGICOPPROC glad_glLogicOp = NULL;\nPFNGLMAP1DPROC glad_glMap1d = NULL;\nPFNGLMAP1FPROC glad_glMap1f = NULL;\nPFNGLMAP2DPROC glad_glMap2d = NULL;\nPFNGLMAP2FPROC glad_glMap2f = NULL;\nPFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;\nPFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;\nPFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL;\nPFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL;\nPFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL;\nPFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL;\nPFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL;\nPFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL;\nPFNGLMATERIALFPROC glad_glMaterialf = NULL;\nPFNGLMATERIALFVPROC glad_glMaterialfv = NULL;\nPFNGLMATERIALIPROC glad_glMateriali = NULL;\nPFNGLMATERIALIVPROC glad_glMaterialiv = NULL;\nPFNGLMATRIXMODEPROC glad_glMatrixMode = NULL;\nPFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;\nPFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;\nPFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;\nPFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL;\nPFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL;\nPFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL;\nPFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL;\nPFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;\nPFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;\nPFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount = NULL;\nPFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;\nPFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;\nPFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;\nPFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount = NULL;\nPFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL;\nPFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL;\nPFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL;\nPFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL;\nPFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL;\nPFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL;\nPFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL;\nPFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL;\nPFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL;\nPFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL;\nPFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL;\nPFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL;\nPFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL;\nPFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL;\nPFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL;\nPFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL;\nPFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL;\nPFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL;\nPFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL;\nPFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL;\nPFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL;\nPFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL;\nPFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL;\nPFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL;\nPFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL;\nPFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL;\nPFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL;\nPFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL;\nPFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL;\nPFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL;\nPFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL;\nPFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = 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;\nPFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL;\nPFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL;\nPFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL;\nPFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL;\nPFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL;\nPFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL;\nPFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL;\nPFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL;\nPFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL;\nPFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL;\nPFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL;\nPFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL;\nPFNGLNEWLISTPROC glad_glNewList = NULL;\nPFNGLNORMAL3BPROC glad_glNormal3b = NULL;\nPFNGLNORMAL3BVPROC glad_glNormal3bv = NULL;\nPFNGLNORMAL3DPROC glad_glNormal3d = NULL;\nPFNGLNORMAL3DVPROC glad_glNormal3dv = NULL;\nPFNGLNORMAL3FPROC glad_glNormal3f = NULL;\nPFNGLNORMAL3FVPROC glad_glNormal3fv = NULL;\nPFNGLNORMAL3IPROC glad_glNormal3i = NULL;\nPFNGLNORMAL3IVPROC glad_glNormal3iv = NULL;\nPFNGLNORMAL3SPROC glad_glNormal3s = NULL;\nPFNGLNORMAL3SVPROC glad_glNormal3sv = NULL;\nPFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL;\nPFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL;\nPFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL;\nPFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;\nPFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;\nPFNGLORTHOPROC glad_glOrtho = NULL;\nPFNGLPASSTHROUGHPROC glad_glPassThrough = NULL;\nPFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;\nPFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;\nPFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;\nPFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL;\nPFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL;\nPFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL;\nPFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;\nPFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;\nPFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL;\nPFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL;\nPFNGLPIXELZOOMPROC glad_glPixelZoom = 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;\nPFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL;\nPFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL;\nPFNGLPOPATTRIBPROC glad_glPopAttrib = NULL;\nPFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL;\nPFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;\nPFNGLPOPMATRIXPROC glad_glPopMatrix = NULL;\nPFNGLPOPNAMEPROC glad_glPopName = NULL;\nPFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox = NULL;\nPFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;\nPFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL;\nPFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;\nPFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;\nPFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;\nPFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;\nPFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;\nPFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;\nPFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;\nPFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;\nPFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;\nPFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;\nPFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;\nPFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;\nPFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;\nPFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;\nPFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;\nPFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;\nPFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;\nPFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;\nPFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;\nPFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;\nPFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;\nPFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;\nPFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;\nPFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;\nPFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;\nPFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;\nPFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;\nPFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;\nPFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;\nPFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;\nPFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;\nPFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;\nPFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;\nPFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;\nPFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;\nPFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL;\nPFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL;\nPFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;\nPFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL;\nPFNGLPUSHNAMEPROC glad_glPushName = NULL;\nPFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;\nPFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL;\nPFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL;\nPFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL;\nPFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL;\nPFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL;\nPFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL;\nPFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL;\nPFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL;\nPFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL;\nPFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL;\nPFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL;\nPFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL;\nPFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL;\nPFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL;\nPFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL;\nPFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL;\nPFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL;\nPFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL;\nPFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL;\nPFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL;\nPFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL;\nPFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL;\nPFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL;\nPFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL;\nPFNGLREADBUFFERPROC glad_glReadBuffer = NULL;\nPFNGLREADPIXELSPROC glad_glReadPixels = NULL;\nPFNGLREADNPIXELSPROC glad_glReadnPixels = NULL;\nPFNGLRECTDPROC glad_glRectd = NULL;\nPFNGLRECTDVPROC glad_glRectdv = NULL;\nPFNGLRECTFPROC glad_glRectf = NULL;\nPFNGLRECTFVPROC glad_glRectfv = NULL;\nPFNGLRECTIPROC glad_glRecti = NULL;\nPFNGLRECTIVPROC glad_glRectiv = NULL;\nPFNGLRECTSPROC glad_glRects = NULL;\nPFNGLRECTSVPROC glad_glRectsv = NULL;\nPFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;\nPFNGLRENDERMODEPROC glad_glRenderMode = NULL;\nPFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;\nPFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;\nPFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;\nPFNGLROTATEDPROC glad_glRotated = NULL;\nPFNGLROTATEFPROC glad_glRotatef = 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;\nPFNGLSCALEDPROC glad_glScaled = NULL;\nPFNGLSCALEFPROC glad_glScalef = NULL;\nPFNGLSCISSORPROC glad_glScissor = NULL;\nPFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;\nPFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;\nPFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;\nPFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL;\nPFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL;\nPFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL;\nPFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL;\nPFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL;\nPFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL;\nPFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL;\nPFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL;\nPFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL;\nPFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL;\nPFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL;\nPFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL;\nPFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL;\nPFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL;\nPFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL;\nPFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL;\nPFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL;\nPFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL;\nPFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL;\nPFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL;\nPFNGLSHADEMODELPROC glad_glShadeModel = NULL;\nPFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;\nPFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;\nPFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;\nPFNGLSPECIALIZESHADERPROC glad_glSpecializeShader = 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;\nPFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;\nPFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL;\nPFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL;\nPFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL;\nPFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL;\nPFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL;\nPFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL;\nPFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL;\nPFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL;\nPFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL;\nPFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL;\nPFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL;\nPFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL;\nPFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL;\nPFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL;\nPFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL;\nPFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL;\nPFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL;\nPFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL;\nPFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL;\nPFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL;\nPFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL;\nPFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL;\nPFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL;\nPFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL;\nPFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL;\nPFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL;\nPFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL;\nPFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL;\nPFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL;\nPFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL;\nPFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL;\nPFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = 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;\nPFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL;\nPFNGLTEXENVFPROC glad_glTexEnvf = NULL;\nPFNGLTEXENVFVPROC glad_glTexEnvfv = NULL;\nPFNGLTEXENVIPROC glad_glTexEnvi = NULL;\nPFNGLTEXENVIVPROC glad_glTexEnviv = NULL;\nPFNGLTEXGENDPROC glad_glTexGend = NULL;\nPFNGLTEXGENDVPROC glad_glTexGendv = NULL;\nPFNGLTEXGENFPROC glad_glTexGenf = NULL;\nPFNGLTEXGENFVPROC glad_glTexGenfv = NULL;\nPFNGLTEXGENIPROC glad_glTexGeni = NULL;\nPFNGLTEXGENIVPROC glad_glTexGeniv = 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;\nPFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;\nPFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;\nPFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;\nPFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;\nPFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;\nPFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;\nPFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;\nPFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;\nPFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL;\nPFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL;\nPFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL;\nPFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL;\nPFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL;\nPFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL;\nPFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL;\nPFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL;\nPFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL;\nPFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL;\nPFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL;\nPFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL;\nPFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL;\nPFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL;\nPFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL;\nPFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL;\nPFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL;\nPFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;\nPFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL;\nPFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL;\nPFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;\nPFNGLTRANSLATEDPROC glad_glTranslated = NULL;\nPFNGLTRANSLATEFPROC glad_glTranslatef = NULL;\nPFNGLUNIFORM1DPROC glad_glUniform1d = NULL;\nPFNGLUNIFORM1DVPROC glad_glUniform1dv = 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;\nPFNGLUNIFORM2DPROC glad_glUniform2d = NULL;\nPFNGLUNIFORM2DVPROC glad_glUniform2dv = 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;\nPFNGLUNIFORM3DPROC glad_glUniform3d = NULL;\nPFNGLUNIFORM3DVPROC glad_glUniform3dv = 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;\nPFNGLUNIFORM4DPROC glad_glUniform4d = NULL;\nPFNGLUNIFORM4DVPROC glad_glUniform4dv = 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;\nPFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;\nPFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;\nPFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;\nPFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;\nPFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;\nPFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;\nPFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;\nPFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;\nPFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;\nPFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;\nPFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;\nPFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;\nPFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;\nPFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;\nPFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;\nPFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;\nPFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;\nPFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;\nPFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;\nPFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;\nPFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL;\nPFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;\nPFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;\nPFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;\nPFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;\nPFNGLVERTEX2DPROC glad_glVertex2d = NULL;\nPFNGLVERTEX2DVPROC glad_glVertex2dv = NULL;\nPFNGLVERTEX2FPROC glad_glVertex2f = NULL;\nPFNGLVERTEX2FVPROC glad_glVertex2fv = NULL;\nPFNGLVERTEX2IPROC glad_glVertex2i = NULL;\nPFNGLVERTEX2IVPROC glad_glVertex2iv = NULL;\nPFNGLVERTEX2SPROC glad_glVertex2s = NULL;\nPFNGLVERTEX2SVPROC glad_glVertex2sv = NULL;\nPFNGLVERTEX3DPROC glad_glVertex3d = NULL;\nPFNGLVERTEX3DVPROC glad_glVertex3dv = NULL;\nPFNGLVERTEX3FPROC glad_glVertex3f = NULL;\nPFNGLVERTEX3FVPROC glad_glVertex3fv = NULL;\nPFNGLVERTEX3IPROC glad_glVertex3i = NULL;\nPFNGLVERTEX3IVPROC glad_glVertex3iv = NULL;\nPFNGLVERTEX3SPROC glad_glVertex3s = NULL;\nPFNGLVERTEX3SVPROC glad_glVertex3sv = NULL;\nPFNGLVERTEX4DPROC glad_glVertex4d = NULL;\nPFNGLVERTEX4DVPROC glad_glVertex4dv = NULL;\nPFNGLVERTEX4FPROC glad_glVertex4f = NULL;\nPFNGLVERTEX4FVPROC glad_glVertex4fv = NULL;\nPFNGLVERTEX4IPROC glad_glVertex4i = NULL;\nPFNGLVERTEX4IVPROC glad_glVertex4iv = NULL;\nPFNGLVERTEX4SPROC glad_glVertex4s = NULL;\nPFNGLVERTEX4SVPROC glad_glVertex4sv = NULL;\nPFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL;\nPFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL;\nPFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL;\nPFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL;\nPFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL;\nPFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL;\nPFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL;\nPFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = 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;\nPFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;\nPFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;\nPFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = 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;\nPFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;\nPFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;\nPFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;\nPFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;\nPFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;\nPFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;\nPFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;\nPFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;\nPFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;\nPFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;\nPFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;\nPFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = 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;\nPFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = 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;\nPFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL;\nPFNGLVIEWPORTPROC glad_glViewport = NULL;\nPFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;\nPFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;\nPFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;\nPFNGLWAITSYNCPROC glad_glWaitSync = NULL;\nPFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL;\nPFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL;\nPFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL;\nPFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL;\nPFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL;\nPFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL;\nPFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL;\nPFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL;\nPFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL;\nPFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL;\nPFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL;\nPFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL;\nPFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL;\nPFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL;\nPFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;\nPFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;\nint GLAD_GL_ARB_clip_control = 0;\nint GLAD_GL_EXT_clip_control = 0;\nPFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT = 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\tglad_glNewList = (PFNGLNEWLISTPROC)load(\"glNewList\");\n\tglad_glEndList = (PFNGLENDLISTPROC)load(\"glEndList\");\n\tglad_glCallList = (PFNGLCALLLISTPROC)load(\"glCallList\");\n\tglad_glCallLists = (PFNGLCALLLISTSPROC)load(\"glCallLists\");\n\tglad_glDeleteLists = (PFNGLDELETELISTSPROC)load(\"glDeleteLists\");\n\tglad_glGenLists = (PFNGLGENLISTSPROC)load(\"glGenLists\");\n\tglad_glListBase = (PFNGLLISTBASEPROC)load(\"glListBase\");\n\tglad_glBegin = (PFNGLBEGINPROC)load(\"glBegin\");\n\tglad_glBitmap = (PFNGLBITMAPPROC)load(\"glBitmap\");\n\tglad_glColor3b = (PFNGLCOLOR3BPROC)load(\"glColor3b\");\n\tglad_glColor3bv = (PFNGLCOLOR3BVPROC)load(\"glColor3bv\");\n\tglad_glColor3d = (PFNGLCOLOR3DPROC)load(\"glColor3d\");\n\tglad_glColor3dv = (PFNGLCOLOR3DVPROC)load(\"glColor3dv\");\n\tglad_glColor3f = (PFNGLCOLOR3FPROC)load(\"glColor3f\");\n\tglad_glColor3fv = (PFNGLCOLOR3FVPROC)load(\"glColor3fv\");\n\tglad_glColor3i = (PFNGLCOLOR3IPROC)load(\"glColor3i\");\n\tglad_glColor3iv = (PFNGLCOLOR3IVPROC)load(\"glColor3iv\");\n\tglad_glColor3s = (PFNGLCOLOR3SPROC)load(\"glColor3s\");\n\tglad_glColor3sv = (PFNGLCOLOR3SVPROC)load(\"glColor3sv\");\n\tglad_glColor3ub = (PFNGLCOLOR3UBPROC)load(\"glColor3ub\");\n\tglad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load(\"glColor3ubv\");\n\tglad_glColor3ui = (PFNGLCOLOR3UIPROC)load(\"glColor3ui\");\n\tglad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load(\"glColor3uiv\");\n\tglad_glColor3us = (PFNGLCOLOR3USPROC)load(\"glColor3us\");\n\tglad_glColor3usv = (PFNGLCOLOR3USVPROC)load(\"glColor3usv\");\n\tglad_glColor4b = (PFNGLCOLOR4BPROC)load(\"glColor4b\");\n\tglad_glColor4bv = (PFNGLCOLOR4BVPROC)load(\"glColor4bv\");\n\tglad_glColor4d = (PFNGLCOLOR4DPROC)load(\"glColor4d\");\n\tglad_glColor4dv = (PFNGLCOLOR4DVPROC)load(\"glColor4dv\");\n\tglad_glColor4f = (PFNGLCOLOR4FPROC)load(\"glColor4f\");\n\tglad_glColor4fv = (PFNGLCOLOR4FVPROC)load(\"glColor4fv\");\n\tglad_glColor4i = (PFNGLCOLOR4IPROC)load(\"glColor4i\");\n\tglad_glColor4iv = (PFNGLCOLOR4IVPROC)load(\"glColor4iv\");\n\tglad_glColor4s = (PFNGLCOLOR4SPROC)load(\"glColor4s\");\n\tglad_glColor4sv = (PFNGLCOLOR4SVPROC)load(\"glColor4sv\");\n\tglad_glColor4ub = (PFNGLCOLOR4UBPROC)load(\"glColor4ub\");\n\tglad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load(\"glColor4ubv\");\n\tglad_glColor4ui = (PFNGLCOLOR4UIPROC)load(\"glColor4ui\");\n\tglad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load(\"glColor4uiv\");\n\tglad_glColor4us = (PFNGLCOLOR4USPROC)load(\"glColor4us\");\n\tglad_glColor4usv = (PFNGLCOLOR4USVPROC)load(\"glColor4usv\");\n\tglad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load(\"glEdgeFlag\");\n\tglad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load(\"glEdgeFlagv\");\n\tglad_glEnd = (PFNGLENDPROC)load(\"glEnd\");\n\tglad_glIndexd = (PFNGLINDEXDPROC)load(\"glIndexd\");\n\tglad_glIndexdv = (PFNGLINDEXDVPROC)load(\"glIndexdv\");\n\tglad_glIndexf = (PFNGLINDEXFPROC)load(\"glIndexf\");\n\tglad_glIndexfv = (PFNGLINDEXFVPROC)load(\"glIndexfv\");\n\tglad_glIndexi = (PFNGLINDEXIPROC)load(\"glIndexi\");\n\tglad_glIndexiv = (PFNGLINDEXIVPROC)load(\"glIndexiv\");\n\tglad_glIndexs = (PFNGLINDEXSPROC)load(\"glIndexs\");\n\tglad_glIndexsv = (PFNGLINDEXSVPROC)load(\"glIndexsv\");\n\tglad_glNormal3b = (PFNGLNORMAL3BPROC)load(\"glNormal3b\");\n\tglad_glNormal3bv = (PFNGLNORMAL3BVPROC)load(\"glNormal3bv\");\n\tglad_glNormal3d = (PFNGLNORMAL3DPROC)load(\"glNormal3d\");\n\tglad_glNormal3dv = (PFNGLNORMAL3DVPROC)load(\"glNormal3dv\");\n\tglad_glNormal3f = (PFNGLNORMAL3FPROC)load(\"glNormal3f\");\n\tglad_glNormal3fv = (PFNGLNORMAL3FVPROC)load(\"glNormal3fv\");\n\tglad_glNormal3i = (PFNGLNORMAL3IPROC)load(\"glNormal3i\");\n\tglad_glNormal3iv = (PFNGLNORMAL3IVPROC)load(\"glNormal3iv\");\n\tglad_glNormal3s = (PFNGLNORMAL3SPROC)load(\"glNormal3s\");\n\tglad_glNormal3sv = (PFNGLNORMAL3SVPROC)load(\"glNormal3sv\");\n\tglad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load(\"glRasterPos2d\");\n\tglad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load(\"glRasterPos2dv\");\n\tglad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load(\"glRasterPos2f\");\n\tglad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load(\"glRasterPos2fv\");\n\tglad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load(\"glRasterPos2i\");\n\tglad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load(\"glRasterPos2iv\");\n\tglad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load(\"glRasterPos2s\");\n\tglad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load(\"glRasterPos2sv\");\n\tglad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load(\"glRasterPos3d\");\n\tglad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load(\"glRasterPos3dv\");\n\tglad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load(\"glRasterPos3f\");\n\tglad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load(\"glRasterPos3fv\");\n\tglad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load(\"glRasterPos3i\");\n\tglad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load(\"glRasterPos3iv\");\n\tglad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load(\"glRasterPos3s\");\n\tglad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load(\"glRasterPos3sv\");\n\tglad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load(\"glRasterPos4d\");\n\tglad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load(\"glRasterPos4dv\");\n\tglad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load(\"glRasterPos4f\");\n\tglad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load(\"glRasterPos4fv\");\n\tglad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load(\"glRasterPos4i\");\n\tglad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load(\"glRasterPos4iv\");\n\tglad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load(\"glRasterPos4s\");\n\tglad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load(\"glRasterPos4sv\");\n\tglad_glRectd = (PFNGLRECTDPROC)load(\"glRectd\");\n\tglad_glRectdv = (PFNGLRECTDVPROC)load(\"glRectdv\");\n\tglad_glRectf = (PFNGLRECTFPROC)load(\"glRectf\");\n\tglad_glRectfv = (PFNGLRECTFVPROC)load(\"glRectfv\");\n\tglad_glRecti = (PFNGLRECTIPROC)load(\"glRecti\");\n\tglad_glRectiv = (PFNGLRECTIVPROC)load(\"glRectiv\");\n\tglad_glRects = (PFNGLRECTSPROC)load(\"glRects\");\n\tglad_glRectsv = (PFNGLRECTSVPROC)load(\"glRectsv\");\n\tglad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load(\"glTexCoord1d\");\n\tglad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load(\"glTexCoord1dv\");\n\tglad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load(\"glTexCoord1f\");\n\tglad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load(\"glTexCoord1fv\");\n\tglad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load(\"glTexCoord1i\");\n\tglad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load(\"glTexCoord1iv\");\n\tglad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load(\"glTexCoord1s\");\n\tglad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load(\"glTexCoord1sv\");\n\tglad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load(\"glTexCoord2d\");\n\tglad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load(\"glTexCoord2dv\");\n\tglad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load(\"glTexCoord2f\");\n\tglad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load(\"glTexCoord2fv\");\n\tglad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load(\"glTexCoord2i\");\n\tglad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load(\"glTexCoord2iv\");\n\tglad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load(\"glTexCoord2s\");\n\tglad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load(\"glTexCoord2sv\");\n\tglad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load(\"glTexCoord3d\");\n\tglad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load(\"glTexCoord3dv\");\n\tglad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load(\"glTexCoord3f\");\n\tglad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load(\"glTexCoord3fv\");\n\tglad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load(\"glTexCoord3i\");\n\tglad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load(\"glTexCoord3iv\");\n\tglad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load(\"glTexCoord3s\");\n\tglad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load(\"glTexCoord3sv\");\n\tglad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load(\"glTexCoord4d\");\n\tglad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load(\"glTexCoord4dv\");\n\tglad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load(\"glTexCoord4f\");\n\tglad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load(\"glTexCoord4fv\");\n\tglad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load(\"glTexCoord4i\");\n\tglad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load(\"glTexCoord4iv\");\n\tglad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load(\"glTexCoord4s\");\n\tglad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load(\"glTexCoord4sv\");\n\tglad_glVertex2d = (PFNGLVERTEX2DPROC)load(\"glVertex2d\");\n\tglad_glVertex2dv = (PFNGLVERTEX2DVPROC)load(\"glVertex2dv\");\n\tglad_glVertex2f = (PFNGLVERTEX2FPROC)load(\"glVertex2f\");\n\tglad_glVertex2fv = (PFNGLVERTEX2FVPROC)load(\"glVertex2fv\");\n\tglad_glVertex2i = (PFNGLVERTEX2IPROC)load(\"glVertex2i\");\n\tglad_glVertex2iv = (PFNGLVERTEX2IVPROC)load(\"glVertex2iv\");\n\tglad_glVertex2s = (PFNGLVERTEX2SPROC)load(\"glVertex2s\");\n\tglad_glVertex2sv = (PFNGLVERTEX2SVPROC)load(\"glVertex2sv\");\n\tglad_glVertex3d = (PFNGLVERTEX3DPROC)load(\"glVertex3d\");\n\tglad_glVertex3dv = (PFNGLVERTEX3DVPROC)load(\"glVertex3dv\");\n\tglad_glVertex3f = (PFNGLVERTEX3FPROC)load(\"glVertex3f\");\n\tglad_glVertex3fv = (PFNGLVERTEX3FVPROC)load(\"glVertex3fv\");\n\tglad_glVertex3i = (PFNGLVERTEX3IPROC)load(\"glVertex3i\");\n\tglad_glVertex3iv = (PFNGLVERTEX3IVPROC)load(\"glVertex3iv\");\n\tglad_glVertex3s = (PFNGLVERTEX3SPROC)load(\"glVertex3s\");\n\tglad_glVertex3sv = (PFNGLVERTEX3SVPROC)load(\"glVertex3sv\");\n\tglad_glVertex4d = (PFNGLVERTEX4DPROC)load(\"glVertex4d\");\n\tglad_glVertex4dv = (PFNGLVERTEX4DVPROC)load(\"glVertex4dv\");\n\tglad_glVertex4f = (PFNGLVERTEX4FPROC)load(\"glVertex4f\");\n\tglad_glVertex4fv = (PFNGLVERTEX4FVPROC)load(\"glVertex4fv\");\n\tglad_glVertex4i = (PFNGLVERTEX4IPROC)load(\"glVertex4i\");\n\tglad_glVertex4iv = (PFNGLVERTEX4IVPROC)load(\"glVertex4iv\");\n\tglad_glVertex4s = (PFNGLVERTEX4SPROC)load(\"glVertex4s\");\n\tglad_glVertex4sv = (PFNGLVERTEX4SVPROC)load(\"glVertex4sv\");\n\tglad_glClipPlane = (PFNGLCLIPPLANEPROC)load(\"glClipPlane\");\n\tglad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load(\"glColorMaterial\");\n\tglad_glFogf = (PFNGLFOGFPROC)load(\"glFogf\");\n\tglad_glFogfv = (PFNGLFOGFVPROC)load(\"glFogfv\");\n\tglad_glFogi = (PFNGLFOGIPROC)load(\"glFogi\");\n\tglad_glFogiv = (PFNGLFOGIVPROC)load(\"glFogiv\");\n\tglad_glLightf = (PFNGLLIGHTFPROC)load(\"glLightf\");\n\tglad_glLightfv = (PFNGLLIGHTFVPROC)load(\"glLightfv\");\n\tglad_glLighti = (PFNGLLIGHTIPROC)load(\"glLighti\");\n\tglad_glLightiv = (PFNGLLIGHTIVPROC)load(\"glLightiv\");\n\tglad_glLightModelf = (PFNGLLIGHTMODELFPROC)load(\"glLightModelf\");\n\tglad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load(\"glLightModelfv\");\n\tglad_glLightModeli = (PFNGLLIGHTMODELIPROC)load(\"glLightModeli\");\n\tglad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load(\"glLightModeliv\");\n\tglad_glLineStipple = (PFNGLLINESTIPPLEPROC)load(\"glLineStipple\");\n\tglad_glMaterialf = (PFNGLMATERIALFPROC)load(\"glMaterialf\");\n\tglad_glMaterialfv = (PFNGLMATERIALFVPROC)load(\"glMaterialfv\");\n\tglad_glMateriali = (PFNGLMATERIALIPROC)load(\"glMateriali\");\n\tglad_glMaterialiv = (PFNGLMATERIALIVPROC)load(\"glMaterialiv\");\n\tglad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load(\"glPolygonStipple\");\n\tglad_glShadeModel = (PFNGLSHADEMODELPROC)load(\"glShadeModel\");\n\tglad_glTexEnvf = (PFNGLTEXENVFPROC)load(\"glTexEnvf\");\n\tglad_glTexEnvfv = (PFNGLTEXENVFVPROC)load(\"glTexEnvfv\");\n\tglad_glTexEnvi = (PFNGLTEXENVIPROC)load(\"glTexEnvi\");\n\tglad_glTexEnviv = (PFNGLTEXENVIVPROC)load(\"glTexEnviv\");\n\tglad_glTexGend = (PFNGLTEXGENDPROC)load(\"glTexGend\");\n\tglad_glTexGendv = (PFNGLTEXGENDVPROC)load(\"glTexGendv\");\n\tglad_glTexGenf = (PFNGLTEXGENFPROC)load(\"glTexGenf\");\n\tglad_glTexGenfv = (PFNGLTEXGENFVPROC)load(\"glTexGenfv\");\n\tglad_glTexGeni = (PFNGLTEXGENIPROC)load(\"glTexGeni\");\n\tglad_glTexGeniv = (PFNGLTEXGENIVPROC)load(\"glTexGeniv\");\n\tglad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load(\"glFeedbackBuffer\");\n\tglad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load(\"glSelectBuffer\");\n\tglad_glRenderMode = (PFNGLRENDERMODEPROC)load(\"glRenderMode\");\n\tglad_glInitNames = (PFNGLINITNAMESPROC)load(\"glInitNames\");\n\tglad_glLoadName = (PFNGLLOADNAMEPROC)load(\"glLoadName\");\n\tglad_glPassThrough = (PFNGLPASSTHROUGHPROC)load(\"glPassThrough\");\n\tglad_glPopName = (PFNGLPOPNAMEPROC)load(\"glPopName\");\n\tglad_glPushName = (PFNGLPUSHNAMEPROC)load(\"glPushName\");\n\tglad_glClearAccum = (PFNGLCLEARACCUMPROC)load(\"glClearAccum\");\n\tglad_glClearIndex = (PFNGLCLEARINDEXPROC)load(\"glClearIndex\");\n\tglad_glIndexMask = (PFNGLINDEXMASKPROC)load(\"glIndexMask\");\n\tglad_glAccum = (PFNGLACCUMPROC)load(\"glAccum\");\n\tglad_glPopAttrib = (PFNGLPOPATTRIBPROC)load(\"glPopAttrib\");\n\tglad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load(\"glPushAttrib\");\n\tglad_glMap1d = (PFNGLMAP1DPROC)load(\"glMap1d\");\n\tglad_glMap1f = (PFNGLMAP1FPROC)load(\"glMap1f\");\n\tglad_glMap2d = (PFNGLMAP2DPROC)load(\"glMap2d\");\n\tglad_glMap2f = (PFNGLMAP2FPROC)load(\"glMap2f\");\n\tglad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load(\"glMapGrid1d\");\n\tglad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load(\"glMapGrid1f\");\n\tglad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load(\"glMapGrid2d\");\n\tglad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load(\"glMapGrid2f\");\n\tglad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load(\"glEvalCoord1d\");\n\tglad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load(\"glEvalCoord1dv\");\n\tglad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load(\"glEvalCoord1f\");\n\tglad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load(\"glEvalCoord1fv\");\n\tglad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load(\"glEvalCoord2d\");\n\tglad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load(\"glEvalCoord2dv\");\n\tglad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load(\"glEvalCoord2f\");\n\tglad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load(\"glEvalCoord2fv\");\n\tglad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load(\"glEvalMesh1\");\n\tglad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load(\"glEvalPoint1\");\n\tglad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load(\"glEvalMesh2\");\n\tglad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load(\"glEvalPoint2\");\n\tglad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load(\"glAlphaFunc\");\n\tglad_glPixelZoom = (PFNGLPIXELZOOMPROC)load(\"glPixelZoom\");\n\tglad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load(\"glPixelTransferf\");\n\tglad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load(\"glPixelTransferi\");\n\tglad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load(\"glPixelMapfv\");\n\tglad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load(\"glPixelMapuiv\");\n\tglad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load(\"glPixelMapusv\");\n\tglad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load(\"glCopyPixels\");\n\tglad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load(\"glDrawPixels\");\n\tglad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load(\"glGetClipPlane\");\n\tglad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load(\"glGetLightfv\");\n\tglad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load(\"glGetLightiv\");\n\tglad_glGetMapdv = (PFNGLGETMAPDVPROC)load(\"glGetMapdv\");\n\tglad_glGetMapfv = (PFNGLGETMAPFVPROC)load(\"glGetMapfv\");\n\tglad_glGetMapiv = (PFNGLGETMAPIVPROC)load(\"glGetMapiv\");\n\tglad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load(\"glGetMaterialfv\");\n\tglad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load(\"glGetMaterialiv\");\n\tglad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load(\"glGetPixelMapfv\");\n\tglad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load(\"glGetPixelMapuiv\");\n\tglad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load(\"glGetPixelMapusv\");\n\tglad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load(\"glGetPolygonStipple\");\n\tglad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load(\"glGetTexEnvfv\");\n\tglad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load(\"glGetTexEnviv\");\n\tglad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load(\"glGetTexGendv\");\n\tglad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load(\"glGetTexGenfv\");\n\tglad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load(\"glGetTexGeniv\");\n\tglad_glIsList = (PFNGLISLISTPROC)load(\"glIsList\");\n\tglad_glFrustum = (PFNGLFRUSTUMPROC)load(\"glFrustum\");\n\tglad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load(\"glLoadIdentity\");\n\tglad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load(\"glLoadMatrixf\");\n\tglad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load(\"glLoadMatrixd\");\n\tglad_glMatrixMode = (PFNGLMATRIXMODEPROC)load(\"glMatrixMode\");\n\tglad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load(\"glMultMatrixf\");\n\tglad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load(\"glMultMatrixd\");\n\tglad_glOrtho = (PFNGLORTHOPROC)load(\"glOrtho\");\n\tglad_glPopMatrix = (PFNGLPOPMATRIXPROC)load(\"glPopMatrix\");\n\tglad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load(\"glPushMatrix\");\n\tglad_glRotated = (PFNGLROTATEDPROC)load(\"glRotated\");\n\tglad_glRotatef = (PFNGLROTATEFPROC)load(\"glRotatef\");\n\tglad_glScaled = (PFNGLSCALEDPROC)load(\"glScaled\");\n\tglad_glScalef = (PFNGLSCALEFPROC)load(\"glScalef\");\n\tglad_glTranslated = (PFNGLTRANSLATEDPROC)load(\"glTranslated\");\n\tglad_glTranslatef = (PFNGLTRANSLATEFPROC)load(\"glTranslatef\");\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_glGetPointerv = (PFNGLGETPOINTERVPROC)load(\"glGetPointerv\");\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\tglad_glArrayElement = (PFNGLARRAYELEMENTPROC)load(\"glArrayElement\");\n\tglad_glColorPointer = (PFNGLCOLORPOINTERPROC)load(\"glColorPointer\");\n\tglad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load(\"glDisableClientState\");\n\tglad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load(\"glEdgeFlagPointer\");\n\tglad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load(\"glEnableClientState\");\n\tglad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load(\"glIndexPointer\");\n\tglad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load(\"glInterleavedArrays\");\n\tglad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load(\"glNormalPointer\");\n\tglad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load(\"glTexCoordPointer\");\n\tglad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load(\"glVertexPointer\");\n\tglad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load(\"glAreTexturesResident\");\n\tglad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load(\"glPrioritizeTextures\");\n\tglad_glIndexub = (PFNGLINDEXUBPROC)load(\"glIndexub\");\n\tglad_glIndexubv = (PFNGLINDEXUBVPROC)load(\"glIndexubv\");\n\tglad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load(\"glPopClientAttrib\");\n\tglad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load(\"glPushClientAttrib\");\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\tglad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load(\"glClientActiveTexture\");\n\tglad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load(\"glMultiTexCoord1d\");\n\tglad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load(\"glMultiTexCoord1dv\");\n\tglad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load(\"glMultiTexCoord1f\");\n\tglad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load(\"glMultiTexCoord1fv\");\n\tglad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load(\"glMultiTexCoord1i\");\n\tglad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load(\"glMultiTexCoord1iv\");\n\tglad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load(\"glMultiTexCoord1s\");\n\tglad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load(\"glMultiTexCoord1sv\");\n\tglad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load(\"glMultiTexCoord2d\");\n\tglad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load(\"glMultiTexCoord2dv\");\n\tglad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load(\"glMultiTexCoord2f\");\n\tglad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load(\"glMultiTexCoord2fv\");\n\tglad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load(\"glMultiTexCoord2i\");\n\tglad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load(\"glMultiTexCoord2iv\");\n\tglad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load(\"glMultiTexCoord2s\");\n\tglad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load(\"glMultiTexCoord2sv\");\n\tglad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load(\"glMultiTexCoord3d\");\n\tglad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load(\"glMultiTexCoord3dv\");\n\tglad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load(\"glMultiTexCoord3f\");\n\tglad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load(\"glMultiTexCoord3fv\");\n\tglad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load(\"glMultiTexCoord3i\");\n\tglad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load(\"glMultiTexCoord3iv\");\n\tglad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load(\"glMultiTexCoord3s\");\n\tglad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load(\"glMultiTexCoord3sv\");\n\tglad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load(\"glMultiTexCoord4d\");\n\tglad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load(\"glMultiTexCoord4dv\");\n\tglad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load(\"glMultiTexCoord4f\");\n\tglad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load(\"glMultiTexCoord4fv\");\n\tglad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load(\"glMultiTexCoord4i\");\n\tglad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load(\"glMultiTexCoord4iv\");\n\tglad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load(\"glMultiTexCoord4s\");\n\tglad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load(\"glMultiTexCoord4sv\");\n\tglad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load(\"glLoadTransposeMatrixf\");\n\tglad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load(\"glLoadTransposeMatrixd\");\n\tglad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load(\"glMultTransposeMatrixf\");\n\tglad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load(\"glMultTransposeMatrixd\");\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_glFogCoordf = (PFNGLFOGCOORDFPROC)load(\"glFogCoordf\");\n\tglad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load(\"glFogCoordfv\");\n\tglad_glFogCoordd = (PFNGLFOGCOORDDPROC)load(\"glFogCoordd\");\n\tglad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load(\"glFogCoorddv\");\n\tglad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load(\"glFogCoordPointer\");\n\tglad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load(\"glSecondaryColor3b\");\n\tglad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load(\"glSecondaryColor3bv\");\n\tglad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load(\"glSecondaryColor3d\");\n\tglad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load(\"glSecondaryColor3dv\");\n\tglad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load(\"glSecondaryColor3f\");\n\tglad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load(\"glSecondaryColor3fv\");\n\tglad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load(\"glSecondaryColor3i\");\n\tglad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load(\"glSecondaryColor3iv\");\n\tglad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load(\"glSecondaryColor3s\");\n\tglad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load(\"glSecondaryColor3sv\");\n\tglad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load(\"glSecondaryColor3ub\");\n\tglad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load(\"glSecondaryColor3ubv\");\n\tglad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load(\"glSecondaryColor3ui\");\n\tglad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load(\"glSecondaryColor3uiv\");\n\tglad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load(\"glSecondaryColor3us\");\n\tglad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load(\"glSecondaryColor3usv\");\n\tglad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load(\"glSecondaryColorPointer\");\n\tglad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load(\"glWindowPos2d\");\n\tglad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load(\"glWindowPos2dv\");\n\tglad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load(\"glWindowPos2f\");\n\tglad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load(\"glWindowPos2fv\");\n\tglad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load(\"glWindowPos2i\");\n\tglad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load(\"glWindowPos2iv\");\n\tglad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load(\"glWindowPos2s\");\n\tglad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load(\"glWindowPos2sv\");\n\tglad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load(\"glWindowPos3d\");\n\tglad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load(\"glWindowPos3dv\");\n\tglad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load(\"glWindowPos3f\");\n\tglad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load(\"glWindowPos3fv\");\n\tglad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load(\"glWindowPos3i\");\n\tglad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load(\"glWindowPos3iv\");\n\tglad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load(\"glWindowPos3s\");\n\tglad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load(\"glWindowPos3sv\");\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 void load_GL_VERSION_4_0(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_0) return;\n\tglad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load(\"glMinSampleShading\");\n\tglad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load(\"glBlendEquationi\");\n\tglad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load(\"glBlendEquationSeparatei\");\n\tglad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load(\"glBlendFunci\");\n\tglad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load(\"glBlendFuncSeparatei\");\n\tglad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load(\"glDrawArraysIndirect\");\n\tglad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load(\"glDrawElementsIndirect\");\n\tglad_glUniform1d = (PFNGLUNIFORM1DPROC)load(\"glUniform1d\");\n\tglad_glUniform2d = (PFNGLUNIFORM2DPROC)load(\"glUniform2d\");\n\tglad_glUniform3d = (PFNGLUNIFORM3DPROC)load(\"glUniform3d\");\n\tglad_glUniform4d = (PFNGLUNIFORM4DPROC)load(\"glUniform4d\");\n\tglad_glUniform1dv = (PFNGLUNIFORM1DVPROC)load(\"glUniform1dv\");\n\tglad_glUniform2dv = (PFNGLUNIFORM2DVPROC)load(\"glUniform2dv\");\n\tglad_glUniform3dv = (PFNGLUNIFORM3DVPROC)load(\"glUniform3dv\");\n\tglad_glUniform4dv = (PFNGLUNIFORM4DVPROC)load(\"glUniform4dv\");\n\tglad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)load(\"glUniformMatrix2dv\");\n\tglad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)load(\"glUniformMatrix3dv\");\n\tglad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)load(\"glUniformMatrix4dv\");\n\tglad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)load(\"glUniformMatrix2x3dv\");\n\tglad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)load(\"glUniformMatrix2x4dv\");\n\tglad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)load(\"glUniformMatrix3x2dv\");\n\tglad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)load(\"glUniformMatrix3x4dv\");\n\tglad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)load(\"glUniformMatrix4x2dv\");\n\tglad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)load(\"glUniformMatrix4x3dv\");\n\tglad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC)load(\"glGetUniformdv\");\n\tglad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)load(\"glGetSubroutineUniformLocation\");\n\tglad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)load(\"glGetSubroutineIndex\");\n\tglad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)load(\"glGetActiveSubroutineUniformiv\");\n\tglad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)load(\"glGetActiveSubroutineUniformName\");\n\tglad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)load(\"glGetActiveSubroutineName\");\n\tglad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)load(\"glUniformSubroutinesuiv\");\n\tglad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)load(\"glGetUniformSubroutineuiv\");\n\tglad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)load(\"glGetProgramStageiv\");\n\tglad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load(\"glPatchParameteri\");\n\tglad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)load(\"glPatchParameterfv\");\n\tglad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load(\"glBindTransformFeedback\");\n\tglad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load(\"glDeleteTransformFeedbacks\");\n\tglad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load(\"glGenTransformFeedbacks\");\n\tglad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load(\"glIsTransformFeedback\");\n\tglad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load(\"glPauseTransformFeedback\");\n\tglad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load(\"glResumeTransformFeedback\");\n\tglad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)load(\"glDrawTransformFeedback\");\n\tglad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)load(\"glDrawTransformFeedbackStream\");\n\tglad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)load(\"glBeginQueryIndexed\");\n\tglad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)load(\"glEndQueryIndexed\");\n\tglad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)load(\"glGetQueryIndexediv\");\n}\nstatic void load_GL_VERSION_4_1(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_1) return;\n\tglad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load(\"glReleaseShaderCompiler\");\n\tglad_glShaderBinary = (PFNGLSHADERBINARYPROC)load(\"glShaderBinary\");\n\tglad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load(\"glGetShaderPrecisionFormat\");\n\tglad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load(\"glDepthRangef\");\n\tglad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load(\"glClearDepthf\");\n\tglad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load(\"glGetProgramBinary\");\n\tglad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load(\"glProgramBinary\");\n\tglad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load(\"glProgramParameteri\");\n\tglad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load(\"glUseProgramStages\");\n\tglad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load(\"glActiveShaderProgram\");\n\tglad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load(\"glCreateShaderProgramv\");\n\tglad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load(\"glBindProgramPipeline\");\n\tglad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load(\"glDeleteProgramPipelines\");\n\tglad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load(\"glGenProgramPipelines\");\n\tglad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load(\"glIsProgramPipeline\");\n\tglad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load(\"glGetProgramPipelineiv\");\n\tglad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load(\"glProgramParameteri\");\n\tglad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load(\"glProgramUniform1i\");\n\tglad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load(\"glProgramUniform1iv\");\n\tglad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load(\"glProgramUniform1f\");\n\tglad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load(\"glProgramUniform1fv\");\n\tglad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)load(\"glProgramUniform1d\");\n\tglad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)load(\"glProgramUniform1dv\");\n\tglad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load(\"glProgramUniform1ui\");\n\tglad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load(\"glProgramUniform1uiv\");\n\tglad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load(\"glProgramUniform2i\");\n\tglad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load(\"glProgramUniform2iv\");\n\tglad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load(\"glProgramUniform2f\");\n\tglad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load(\"glProgramUniform2fv\");\n\tglad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)load(\"glProgramUniform2d\");\n\tglad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)load(\"glProgramUniform2dv\");\n\tglad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load(\"glProgramUniform2ui\");\n\tglad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load(\"glProgramUniform2uiv\");\n\tglad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load(\"glProgramUniform3i\");\n\tglad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load(\"glProgramUniform3iv\");\n\tglad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load(\"glProgramUniform3f\");\n\tglad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load(\"glProgramUniform3fv\");\n\tglad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)load(\"glProgramUniform3d\");\n\tglad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)load(\"glProgramUniform3dv\");\n\tglad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load(\"glProgramUniform3ui\");\n\tglad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load(\"glProgramUniform3uiv\");\n\tglad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load(\"glProgramUniform4i\");\n\tglad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load(\"glProgramUniform4iv\");\n\tglad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load(\"glProgramUniform4f\");\n\tglad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load(\"glProgramUniform4fv\");\n\tglad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)load(\"glProgramUniform4d\");\n\tglad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)load(\"glProgramUniform4dv\");\n\tglad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load(\"glProgramUniform4ui\");\n\tglad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load(\"glProgramUniform4uiv\");\n\tglad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load(\"glProgramUniformMatrix2fv\");\n\tglad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load(\"glProgramUniformMatrix3fv\");\n\tglad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load(\"glProgramUniformMatrix4fv\");\n\tglad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)load(\"glProgramUniformMatrix2dv\");\n\tglad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)load(\"glProgramUniformMatrix3dv\");\n\tglad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)load(\"glProgramUniformMatrix4dv\");\n\tglad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load(\"glProgramUniformMatrix2x3fv\");\n\tglad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load(\"glProgramUniformMatrix3x2fv\");\n\tglad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load(\"glProgramUniformMatrix2x4fv\");\n\tglad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load(\"glProgramUniformMatrix4x2fv\");\n\tglad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load(\"glProgramUniformMatrix3x4fv\");\n\tglad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load(\"glProgramUniformMatrix4x3fv\");\n\tglad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)load(\"glProgramUniformMatrix2x3dv\");\n\tglad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)load(\"glProgramUniformMatrix3x2dv\");\n\tglad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)load(\"glProgramUniformMatrix2x4dv\");\n\tglad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)load(\"glProgramUniformMatrix4x2dv\");\n\tglad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)load(\"glProgramUniformMatrix3x4dv\");\n\tglad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)load(\"glProgramUniformMatrix4x3dv\");\n\tglad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load(\"glValidateProgramPipeline\");\n\tglad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load(\"glGetProgramPipelineInfoLog\");\n\tglad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)load(\"glVertexAttribL1d\");\n\tglad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)load(\"glVertexAttribL2d\");\n\tglad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)load(\"glVertexAttribL3d\");\n\tglad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)load(\"glVertexAttribL4d\");\n\tglad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)load(\"glVertexAttribL1dv\");\n\tglad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)load(\"glVertexAttribL2dv\");\n\tglad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)load(\"glVertexAttribL3dv\");\n\tglad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)load(\"glVertexAttribL4dv\");\n\tglad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)load(\"glVertexAttribLPointer\");\n\tglad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)load(\"glGetVertexAttribLdv\");\n\tglad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)load(\"glViewportArrayv\");\n\tglad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)load(\"glViewportIndexedf\");\n\tglad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)load(\"glViewportIndexedfv\");\n\tglad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC)load(\"glScissorArrayv\");\n\tglad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)load(\"glScissorIndexed\");\n\tglad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)load(\"glScissorIndexedv\");\n\tglad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)load(\"glDepthRangeArrayv\");\n\tglad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)load(\"glDepthRangeIndexed\");\n\tglad_glGetFloati_v = (PFNGLGETFLOATI_VPROC)load(\"glGetFloati_v\");\n\tglad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)load(\"glGetDoublei_v\");\n}\nstatic void load_GL_VERSION_4_2(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_2) return;\n\tglad_glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)load(\"glDrawArraysInstancedBaseInstance\");\n\tglad_glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)load(\"glDrawElementsInstancedBaseInstance\");\n\tglad_glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)load(\"glDrawElementsInstancedBaseVertexBaseInstance\");\n\tglad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load(\"glGetInternalformativ\");\n\tglad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)load(\"glGetActiveAtomicCounterBufferiv\");\n\tglad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load(\"glBindImageTexture\");\n\tglad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load(\"glMemoryBarrier\");\n\tglad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)load(\"glTexStorage1D\");\n\tglad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load(\"glTexStorage2D\");\n\tglad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load(\"glTexStorage3D\");\n\tglad_glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)load(\"glDrawTransformFeedbackInstanced\");\n\tglad_glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)load(\"glDrawTransformFeedbackStreamInstanced\");\n}\nstatic void load_GL_VERSION_4_3(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_3) return;\n\tglad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC)load(\"glClearBufferData\");\n\tglad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC)load(\"glClearBufferSubData\");\n\tglad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load(\"glDispatchCompute\");\n\tglad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load(\"glDispatchComputeIndirect\");\n\tglad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load(\"glCopyImageSubData\");\n\tglad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load(\"glFramebufferParameteri\");\n\tglad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load(\"glGetFramebufferParameteriv\");\n\tglad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC)load(\"glGetInternalformati64v\");\n\tglad_glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC)load(\"glInvalidateTexSubImage\");\n\tglad_glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC)load(\"glInvalidateTexImage\");\n\tglad_glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC)load(\"glInvalidateBufferSubData\");\n\tglad_glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC)load(\"glInvalidateBufferData\");\n\tglad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load(\"glInvalidateFramebuffer\");\n\tglad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load(\"glInvalidateSubFramebuffer\");\n\tglad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC)load(\"glMultiDrawArraysIndirect\");\n\tglad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC)load(\"glMultiDrawElementsIndirect\");\n\tglad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load(\"glGetProgramInterfaceiv\");\n\tglad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load(\"glGetProgramResourceIndex\");\n\tglad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load(\"glGetProgramResourceName\");\n\tglad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load(\"glGetProgramResourceiv\");\n\tglad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load(\"glGetProgramResourceLocation\");\n\tglad_glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)load(\"glGetProgramResourceLocationIndex\");\n\tglad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC)load(\"glShaderStorageBlockBinding\");\n\tglad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load(\"glTexBufferRange\");\n\tglad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load(\"glTexStorage2DMultisample\");\n\tglad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load(\"glTexStorage3DMultisample\");\n\tglad_glTextureView = (PFNGLTEXTUREVIEWPROC)load(\"glTextureView\");\n\tglad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load(\"glBindVertexBuffer\");\n\tglad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load(\"glVertexAttribFormat\");\n\tglad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load(\"glVertexAttribIFormat\");\n\tglad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load(\"glVertexAttribLFormat\");\n\tglad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load(\"glVertexAttribBinding\");\n\tglad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load(\"glVertexBindingDivisor\");\n\tglad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load(\"glDebugMessageControl\");\n\tglad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load(\"glDebugMessageInsert\");\n\tglad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load(\"glDebugMessageCallback\");\n\tglad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load(\"glGetDebugMessageLog\");\n\tglad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load(\"glPushDebugGroup\");\n\tglad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load(\"glPopDebugGroup\");\n\tglad_glObjectLabel = (PFNGLOBJECTLABELPROC)load(\"glObjectLabel\");\n\tglad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load(\"glGetObjectLabel\");\n\tglad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load(\"glObjectPtrLabel\");\n\tglad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load(\"glGetObjectPtrLabel\");\n\tglad_glGetPointerv = (PFNGLGETPOINTERVPROC)load(\"glGetPointerv\");\n}\nstatic void load_GL_VERSION_4_4(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_4) return;\n\tglad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load(\"glBufferStorage\");\n\tglad_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)load(\"glClearTexImage\");\n\tglad_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)load(\"glClearTexSubImage\");\n\tglad_glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC)load(\"glBindBuffersBase\");\n\tglad_glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC)load(\"glBindBuffersRange\");\n\tglad_glBindTextures = (PFNGLBINDTEXTURESPROC)load(\"glBindTextures\");\n\tglad_glBindSamplers = (PFNGLBINDSAMPLERSPROC)load(\"glBindSamplers\");\n\tglad_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)load(\"glBindImageTextures\");\n\tglad_glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)load(\"glBindVertexBuffers\");\n}\nstatic void load_GL_VERSION_4_5(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_5) return;\n\tglad_glClipControl = (PFNGLCLIPCONTROLPROC)load(\"glClipControl\");\n\tglad_glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)load(\"glCreateTransformFeedbacks\");\n\tglad_glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)load(\"glTransformFeedbackBufferBase\");\n\tglad_glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)load(\"glTransformFeedbackBufferRange\");\n\tglad_glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)load(\"glGetTransformFeedbackiv\");\n\tglad_glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)load(\"glGetTransformFeedbacki_v\");\n\tglad_glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)load(\"glGetTransformFeedbacki64_v\");\n\tglad_glCreateBuffers = (PFNGLCREATEBUFFERSPROC)load(\"glCreateBuffers\");\n\tglad_glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)load(\"glNamedBufferStorage\");\n\tglad_glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)load(\"glNamedBufferData\");\n\tglad_glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)load(\"glNamedBufferSubData\");\n\tglad_glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)load(\"glCopyNamedBufferSubData\");\n\tglad_glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)load(\"glClearNamedBufferData\");\n\tglad_glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)load(\"glClearNamedBufferSubData\");\n\tglad_glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)load(\"glMapNamedBuffer\");\n\tglad_glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)load(\"glMapNamedBufferRange\");\n\tglad_glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)load(\"glUnmapNamedBuffer\");\n\tglad_glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)load(\"glFlushMappedNamedBufferRange\");\n\tglad_glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)load(\"glGetNamedBufferParameteriv\");\n\tglad_glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)load(\"glGetNamedBufferParameteri64v\");\n\tglad_glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)load(\"glGetNamedBufferPointerv\");\n\tglad_glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)load(\"glGetNamedBufferSubData\");\n\tglad_glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)load(\"glCreateFramebuffers\");\n\tglad_glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)load(\"glNamedFramebufferRenderbuffer\");\n\tglad_glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)load(\"glNamedFramebufferParameteri\");\n\tglad_glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)load(\"glNamedFramebufferTexture\");\n\tglad_glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)load(\"glNamedFramebufferTextureLayer\");\n\tglad_glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)load(\"glNamedFramebufferDrawBuffer\");\n\tglad_glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)load(\"glNamedFramebufferDrawBuffers\");\n\tglad_glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)load(\"glNamedFramebufferReadBuffer\");\n\tglad_glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)load(\"glInvalidateNamedFramebufferData\");\n\tglad_glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)load(\"glInvalidateNamedFramebufferSubData\");\n\tglad_glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)load(\"glClearNamedFramebufferiv\");\n\tglad_glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)load(\"glClearNamedFramebufferuiv\");\n\tglad_glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)load(\"glClearNamedFramebufferfv\");\n\tglad_glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)load(\"glClearNamedFramebufferfi\");\n\tglad_glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)load(\"glBlitNamedFramebuffer\");\n\tglad_glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)load(\"glCheckNamedFramebufferStatus\");\n\tglad_glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)load(\"glGetNamedFramebufferParameteriv\");\n\tglad_glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load(\"glGetNamedFramebufferAttachmentParameteriv\");\n\tglad_glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)load(\"glCreateRenderbuffers\");\n\tglad_glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)load(\"glNamedRenderbufferStorage\");\n\tglad_glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)load(\"glNamedRenderbufferStorageMultisample\");\n\tglad_glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)load(\"glGetNamedRenderbufferParameteriv\");\n\tglad_glCreateTextures = (PFNGLCREATETEXTURESPROC)load(\"glCreateTextures\");\n\tglad_glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)load(\"glTextureBuffer\");\n\tglad_glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)load(\"glTextureBufferRange\");\n\tglad_glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)load(\"glTextureStorage1D\");\n\tglad_glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)load(\"glTextureStorage2D\");\n\tglad_glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)load(\"glTextureStorage3D\");\n\tglad_glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)load(\"glTextureStorage2DMultisample\");\n\tglad_glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)load(\"glTextureStorage3DMultisample\");\n\tglad_glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)load(\"glTextureSubImage1D\");\n\tglad_glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)load(\"glTextureSubImage2D\");\n\tglad_glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)load(\"glTextureSubImage3D\");\n\tglad_glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)load(\"glCompressedTextureSubImage1D\");\n\tglad_glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)load(\"glCompressedTextureSubImage2D\");\n\tglad_glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)load(\"glCompressedTextureSubImage3D\");\n\tglad_glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)load(\"glCopyTextureSubImage1D\");\n\tglad_glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)load(\"glCopyTextureSubImage2D\");\n\tglad_glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)load(\"glCopyTextureSubImage3D\");\n\tglad_glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)load(\"glTextureParameterf\");\n\tglad_glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)load(\"glTextureParameterfv\");\n\tglad_glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)load(\"glTextureParameteri\");\n\tglad_glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)load(\"glTextureParameterIiv\");\n\tglad_glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)load(\"glTextureParameterIuiv\");\n\tglad_glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)load(\"glTextureParameteriv\");\n\tglad_glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)load(\"glGenerateTextureMipmap\");\n\tglad_glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)load(\"glBindTextureUnit\");\n\tglad_glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)load(\"glGetTextureImage\");\n\tglad_glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)load(\"glGetCompressedTextureImage\");\n\tglad_glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)load(\"glGetTextureLevelParameterfv\");\n\tglad_glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)load(\"glGetTextureLevelParameteriv\");\n\tglad_glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)load(\"glGetTextureParameterfv\");\n\tglad_glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)load(\"glGetTextureParameterIiv\");\n\tglad_glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)load(\"glGetTextureParameterIuiv\");\n\tglad_glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)load(\"glGetTextureParameteriv\");\n\tglad_glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)load(\"glCreateVertexArrays\");\n\tglad_glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)load(\"glDisableVertexArrayAttrib\");\n\tglad_glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)load(\"glEnableVertexArrayAttrib\");\n\tglad_glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)load(\"glVertexArrayElementBuffer\");\n\tglad_glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)load(\"glVertexArrayVertexBuffer\");\n\tglad_glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)load(\"glVertexArrayVertexBuffers\");\n\tglad_glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)load(\"glVertexArrayAttribBinding\");\n\tglad_glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)load(\"glVertexArrayAttribFormat\");\n\tglad_glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)load(\"glVertexArrayAttribIFormat\");\n\tglad_glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)load(\"glVertexArrayAttribLFormat\");\n\tglad_glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)load(\"glVertexArrayBindingDivisor\");\n\tglad_glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)load(\"glGetVertexArrayiv\");\n\tglad_glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)load(\"glGetVertexArrayIndexediv\");\n\tglad_glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)load(\"glGetVertexArrayIndexed64iv\");\n\tglad_glCreateSamplers = (PFNGLCREATESAMPLERSPROC)load(\"glCreateSamplers\");\n\tglad_glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)load(\"glCreateProgramPipelines\");\n\tglad_glCreateQueries = (PFNGLCREATEQUERIESPROC)load(\"glCreateQueries\");\n\tglad_glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)load(\"glGetQueryBufferObjecti64v\");\n\tglad_glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)load(\"glGetQueryBufferObjectiv\");\n\tglad_glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)load(\"glGetQueryBufferObjectui64v\");\n\tglad_glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)load(\"glGetQueryBufferObjectuiv\");\n\tglad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)load(\"glMemoryBarrierByRegion\");\n\tglad_glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)load(\"glGetTextureSubImage\");\n\tglad_glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)load(\"glGetCompressedTextureSubImage\");\n\tglad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)load(\"glGetGraphicsResetStatus\");\n\tglad_glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC)load(\"glGetnCompressedTexImage\");\n\tglad_glGetnTexImage = (PFNGLGETNTEXIMAGEPROC)load(\"glGetnTexImage\");\n\tglad_glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC)load(\"glGetnUniformdv\");\n\tglad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)load(\"glGetnUniformfv\");\n\tglad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)load(\"glGetnUniformiv\");\n\tglad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)load(\"glGetnUniformuiv\");\n\tglad_glReadnPixels = (PFNGLREADNPIXELSPROC)load(\"glReadnPixels\");\n\tglad_glGetnMapdv = (PFNGLGETNMAPDVPROC)load(\"glGetnMapdv\");\n\tglad_glGetnMapfv = (PFNGLGETNMAPFVPROC)load(\"glGetnMapfv\");\n\tglad_glGetnMapiv = (PFNGLGETNMAPIVPROC)load(\"glGetnMapiv\");\n\tglad_glGetnPixelMapfv = (PFNGLGETNPIXELMAPFVPROC)load(\"glGetnPixelMapfv\");\n\tglad_glGetnPixelMapuiv = (PFNGLGETNPIXELMAPUIVPROC)load(\"glGetnPixelMapuiv\");\n\tglad_glGetnPixelMapusv = (PFNGLGETNPIXELMAPUSVPROC)load(\"glGetnPixelMapusv\");\n\tglad_glGetnPolygonStipple = (PFNGLGETNPOLYGONSTIPPLEPROC)load(\"glGetnPolygonStipple\");\n\tglad_glGetnColorTable = (PFNGLGETNCOLORTABLEPROC)load(\"glGetnColorTable\");\n\tglad_glGetnConvolutionFilter = (PFNGLGETNCONVOLUTIONFILTERPROC)load(\"glGetnConvolutionFilter\");\n\tglad_glGetnSeparableFilter = (PFNGLGETNSEPARABLEFILTERPROC)load(\"glGetnSeparableFilter\");\n\tglad_glGetnHistogram = (PFNGLGETNHISTOGRAMPROC)load(\"glGetnHistogram\");\n\tglad_glGetnMinmax = (PFNGLGETNMINMAXPROC)load(\"glGetnMinmax\");\n\tglad_glTextureBarrier = (PFNGLTEXTUREBARRIERPROC)load(\"glTextureBarrier\");\n}\nstatic void load_GL_VERSION_4_6(GLADloadproc load) {\n\tif(!GLAD_GL_VERSION_4_6) return;\n\tglad_glSpecializeShader = (PFNGLSPECIALIZESHADERPROC)load(\"glSpecializeShader\");\n\tglad_glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)load(\"glMultiDrawArraysIndirectCount\");\n\tglad_glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)load(\"glMultiDrawElementsIndirectCount\");\n\tglad_glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)load(\"glPolygonOffsetClamp\");\n}\nstatic void load_GL_ARB_clip_control(GLADloadproc load) {\n\tif(!GLAD_GL_ARB_clip_control) return;\n\tglad_glClipControl = (PFNGLCLIPCONTROLPROC)load(\"glClipControl\");\n}\nstatic int find_extensionsGL(void) {\n\tif (!get_exts()) return 0;\n\tGLAD_GL_ARB_clip_control = has_ext(\"GL_ARB_clip_control\");\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\tGLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4;\n\tGLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4;\n\tGLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4;\n\tGLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4;\n\tGLAD_GL_VERSION_4_4 = (major == 4 && minor >= 4) || major > 4;\n\tGLAD_GL_VERSION_4_5 = (major == 4 && minor >= 5) || major > 4;\n\tGLAD_GL_VERSION_4_6 = (major == 4 && minor >= 6) || major > 4;\n\tif (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 6)) {\n\t\tmax_loaded_major = 4;\n\t\tmax_loaded_minor = 6;\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\tload_GL_VERSION_4_0(load);\n\tload_GL_VERSION_4_1(load);\n\tload_GL_VERSION_4_2(load);\n\tload_GL_VERSION_4_3(load);\n\tload_GL_VERSION_4_4(load);\n\tload_GL_VERSION_4_5(load);\n\tload_GL_VERSION_4_6(load);\n\n\tif (!find_extensionsGL()) return 0;\n\tload_GL_ARB_clip_control(load);\n\treturn GLVersion.major != 0 || GLVersion.minor != 0;\n}\n\nstatic void load_GL_ES_VERSION_2_0(GLADloadproc load) {\n\tif(!GLAD_GL_ES_VERSION_2_0) return;\n\tglad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load(\"glActiveTexture\");\n\tglad_glAttachShader = (PFNGLATTACHSHADERPROC)load(\"glAttachShader\");\n\tglad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load(\"glBindAttribLocation\");\n\tglad_glBindBuffer = (PFNGLBINDBUFFERPROC)load(\"glBindBuffer\");\n\tglad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load(\"glBindFramebuffer\");\n\tglad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load(\"glBindRenderbuffer\");\n\tglad_glBindTexture = (PFNGLBINDTEXTUREPROC)load(\"glBindTexture\");\n\tglad_glBlendColor = (PFNGLBLENDCOLORPROC)load(\"glBlendColor\");\n\tglad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load(\"glBlendEquation\");\n\tglad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load(\"glBlendEquationSeparate\");\n\tglad_glBlendFunc = (PFNGLBLENDFUNCPROC)load(\"glBlendFunc\");\n\tglad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load(\"glBlendFuncSeparate\");\n\tglad_glBufferData = (PFNGLBUFFERDATAPROC)load(\"glBufferData\");\n\tglad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load(\"glBufferSubData\");\n\tglad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load(\"glCheckFramebufferStatus\");\n\tglad_glClear = (PFNGLCLEARPROC)load(\"glClear\");\n\tglad_glClearColor = (PFNGLCLEARCOLORPROC)load(\"glClearColor\");\n\tglad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load(\"glClearDepthf\");\n\tglad_glClearStencil = (PFNGLCLEARSTENCILPROC)load(\"glClearStencil\");\n\tglad_glColorMask = (PFNGLCOLORMASKPROC)load(\"glColorMask\");\n\tglad_glCompileShader = (PFNGLCOMPILESHADERPROC)load(\"glCompileShader\");\n\tglad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load(\"glCompressedTexImage2D\");\n\tglad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load(\"glCompressedTexSubImage2D\");\n\tglad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load(\"glCopyTexImage2D\");\n\tglad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load(\"glCopyTexSubImage2D\");\n\tglad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load(\"glCreateProgram\");\n\tglad_glCreateShader = (PFNGLCREATESHADERPROC)load(\"glCreateShader\");\n\tglad_glCullFace = (PFNGLCULLFACEPROC)load(\"glCullFace\");\n\tglad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load(\"glDeleteBuffers\");\n\tglad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load(\"glDeleteFramebuffers\");\n\tglad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load(\"glDeleteProgram\");\n\tglad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load(\"glDeleteRenderbuffers\");\n\tglad_glDeleteShader = (PFNGLDELETESHADERPROC)load(\"glDeleteShader\");\n\tglad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load(\"glDeleteTextures\");\n\tglad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load(\"glDepthFunc\");\n\tglad_glDepthMask = (PFNGLDEPTHMASKPROC)load(\"glDepthMask\");\n\tglad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load(\"glDepthRangef\");\n\tglad_glDetachShader = (PFNGLDETACHSHADERPROC)load(\"glDetachShader\");\n\tglad_glDisable = (PFNGLDISABLEPROC)load(\"glDisable\");\n\tglad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load(\"glDisableVertexAttribArray\");\n\tglad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load(\"glDrawArrays\");\n\tglad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load(\"glDrawElements\");\n\tglad_glEnable = (PFNGLENABLEPROC)load(\"glEnable\");\n\tglad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load(\"glEnableVertexAttribArray\");\n\tglad_glFinish = (PFNGLFINISHPROC)load(\"glFinish\");\n\tglad_glFlush = (PFNGLFLUSHPROC)load(\"glFlush\");\n\tglad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load(\"glFramebufferRenderbuffer\");\n\tglad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load(\"glFramebufferTexture2D\");\n\tglad_glFrontFace = (PFNGLFRONTFACEPROC)load(\"glFrontFace\");\n\tglad_glGenBuffers = (PFNGLGENBUFFERSPROC)load(\"glGenBuffers\");\n\tglad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load(\"glGenerateMipmap\");\n\tglad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load(\"glGenFramebuffers\");\n\tglad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load(\"glGenRenderbuffers\");\n\tglad_glGenTextures = (PFNGLGENTEXTURESPROC)load(\"glGenTextures\");\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_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load(\"glGetBooleanv\");\n\tglad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load(\"glGetBufferParameteriv\");\n\tglad_glGetError = (PFNGLGETERRORPROC)load(\"glGetError\");\n\tglad_glGetFloatv = (PFNGLGETFLOATVPROC)load(\"glGetFloatv\");\n\tglad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load(\"glGetFramebufferAttachmentParameteriv\");\n\tglad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load(\"glGetIntegerv\");\n\tglad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load(\"glGetProgramiv\");\n\tglad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load(\"glGetProgramInfoLog\");\n\tglad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load(\"glGetRenderbufferParameteriv\");\n\tglad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load(\"glGetShaderiv\");\n\tglad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load(\"glGetShaderInfoLog\");\n\tglad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load(\"glGetShaderPrecisionFormat\");\n\tglad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load(\"glGetShaderSource\");\n\tglad_glGetString = (PFNGLGETSTRINGPROC)load(\"glGetString\");\n\tglad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load(\"glGetTexParameterfv\");\n\tglad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load(\"glGetTexParameteriv\");\n\tglad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load(\"glGetUniformfv\");\n\tglad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load(\"glGetUniformiv\");\n\tglad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load(\"glGetUniformLocation\");\n\tglad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load(\"glGetVertexAttribfv\");\n\tglad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load(\"glGetVertexAttribiv\");\n\tglad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load(\"glGetVertexAttribPointerv\");\n\tglad_glHint = (PFNGLHINTPROC)load(\"glHint\");\n\tglad_glIsBuffer = (PFNGLISBUFFERPROC)load(\"glIsBuffer\");\n\tglad_glIsEnabled = (PFNGLISENABLEDPROC)load(\"glIsEnabled\");\n\tglad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load(\"glIsFramebuffer\");\n\tglad_glIsProgram = (PFNGLISPROGRAMPROC)load(\"glIsProgram\");\n\tglad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load(\"glIsRenderbuffer\");\n\tglad_glIsShader = (PFNGLISSHADERPROC)load(\"glIsShader\");\n\tglad_glIsTexture = (PFNGLISTEXTUREPROC)load(\"glIsTexture\");\n\tglad_glLineWidth = (PFNGLLINEWIDTHPROC)load(\"glLineWidth\");\n\tglad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load(\"glLinkProgram\");\n\tglad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load(\"glPixelStorei\");\n\tglad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load(\"glPolygonOffset\");\n\tglad_glReadPixels = (PFNGLREADPIXELSPROC)load(\"glReadPixels\");\n\tglad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load(\"glReleaseShaderCompiler\");\n\tglad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load(\"glRenderbufferStorage\");\n\tglad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load(\"glSampleCoverage\");\n\tglad_glScissor = (PFNGLSCISSORPROC)load(\"glScissor\");\n\tglad_glShaderBinary = (PFNGLSHADERBINARYPROC)load(\"glShaderBinary\");\n\tglad_glShaderSource = (PFNGLSHADERSOURCEPROC)load(\"glShaderSource\");\n\tglad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load(\"glStencilFunc\");\n\tglad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load(\"glStencilFuncSeparate\");\n\tglad_glStencilMask = (PFNGLSTENCILMASKPROC)load(\"glStencilMask\");\n\tglad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load(\"glStencilMaskSeparate\");\n\tglad_glStencilOp = (PFNGLSTENCILOPPROC)load(\"glStencilOp\");\n\tglad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load(\"glStencilOpSeparate\");\n\tglad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load(\"glTexImage2D\");\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_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load(\"glTexSubImage2D\");\n\tglad_glUniform1f = (PFNGLUNIFORM1FPROC)load(\"glUniform1f\");\n\tglad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load(\"glUniform1fv\");\n\tglad_glUniform1i = (PFNGLUNIFORM1IPROC)load(\"glUniform1i\");\n\tglad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load(\"glUniform1iv\");\n\tglad_glUniform2f = (PFNGLUNIFORM2FPROC)load(\"glUniform2f\");\n\tglad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load(\"glUniform2fv\");\n\tglad_glUniform2i = (PFNGLUNIFORM2IPROC)load(\"glUniform2i\");\n\tglad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load(\"glUniform2iv\");\n\tglad_glUniform3f = (PFNGLUNIFORM3FPROC)load(\"glUniform3f\");\n\tglad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load(\"glUniform3fv\");\n\tglad_glUniform3i = (PFNGLUNIFORM3IPROC)load(\"glUniform3i\");\n\tglad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load(\"glUniform3iv\");\n\tglad_glUniform4f = (PFNGLUNIFORM4FPROC)load(\"glUniform4f\");\n\tglad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load(\"glUniform4fv\");\n\tglad_glUniform4i = (PFNGLUNIFORM4IPROC)load(\"glUniform4i\");\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_glUseProgram = (PFNGLUSEPROGRAMPROC)load(\"glUseProgram\");\n\tglad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load(\"glValidateProgram\");\n\tglad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load(\"glVertexAttrib1f\");\n\tglad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load(\"glVertexAttrib1fv\");\n\tglad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load(\"glVertexAttrib2f\");\n\tglad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load(\"glVertexAttrib2fv\");\n\tglad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load(\"glVertexAttrib3f\");\n\tglad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load(\"glVertexAttrib3fv\");\n\tglad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load(\"glVertexAttrib4f\");\n\tglad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load(\"glVertexAttrib4fv\");\n\tglad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load(\"glVertexAttribPointer\");\n\tglad_glViewport = (PFNGLVIEWPORTPROC)load(\"glViewport\");\n}\nstatic void load_GL_ES_VERSION_3_0(GLADloadproc load) {\n\tif(!GLAD_GL_ES_VERSION_3_0) return;\n\tglad_glReadBuffer = (PFNGLREADBUFFERPROC)load(\"glReadBuffer\");\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\tglad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load(\"glCompressedTexImage3D\");\n\tglad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load(\"glCompressedTexSubImage3D\");\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_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load(\"glGetQueryObjectuiv\");\n\tglad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load(\"glUnmapBuffer\");\n\tglad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load(\"glGetBufferPointerv\");\n\tglad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load(\"glDrawBuffers\");\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\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\tglad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load(\"glGetIntegeri_v\");\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_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load(\"glVertexAttribIPointer\");\n\tglad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load(\"glGetVertexAttribIiv\");\n\tglad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load(\"glGetVertexAttribIuiv\");\n\tglad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load(\"glVertexAttribI4i\");\n\tglad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load(\"glVertexAttribI4ui\");\n\tglad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load(\"glVertexAttribI4iv\");\n\tglad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load(\"glVertexAttribI4uiv\");\n\tglad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load(\"glGetUniformuiv\");\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_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_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load(\"glCopyBufferSubData\");\n\tglad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load(\"glGetUniformIndices\");\n\tglad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load(\"glGetActiveUniformsiv\");\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_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load(\"glDrawArraysInstanced\");\n\tglad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load(\"glDrawElementsInstanced\");\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_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_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load(\"glGetSamplerParameteriv\");\n\tglad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load(\"glGetSamplerParameterfv\");\n\tglad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load(\"glVertexAttribDivisor\");\n\tglad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load(\"glBindTransformFeedback\");\n\tglad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load(\"glDeleteTransformFeedbacks\");\n\tglad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load(\"glGenTransformFeedbacks\");\n\tglad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load(\"glIsTransformFeedback\");\n\tglad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load(\"glPauseTransformFeedback\");\n\tglad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load(\"glResumeTransformFeedback\");\n\tglad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load(\"glGetProgramBinary\");\n\tglad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load(\"glProgramBinary\");\n\tglad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load(\"glProgramParameteri\");\n\tglad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load(\"glInvalidateFramebuffer\");\n\tglad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load(\"glInvalidateSubFramebuffer\");\n\tglad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load(\"glTexStorage2D\");\n\tglad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load(\"glTexStorage3D\");\n\tglad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load(\"glGetInternalformativ\");\n}\nstatic void load_GL_ES_VERSION_3_1(GLADloadproc load) {\n\tif(!GLAD_GL_ES_VERSION_3_1) return;\n\tglad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load(\"glDispatchCompute\");\n\tglad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load(\"glDispatchComputeIndirect\");\n\tglad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load(\"glDrawArraysIndirect\");\n\tglad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load(\"glDrawElementsIndirect\");\n\tglad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load(\"glFramebufferParameteri\");\n\tglad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load(\"glGetFramebufferParameteriv\");\n\tglad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load(\"glGetProgramInterfaceiv\");\n\tglad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load(\"glGetProgramResourceIndex\");\n\tglad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load(\"glGetProgramResourceName\");\n\tglad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load(\"glGetProgramResourceiv\");\n\tglad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load(\"glGetProgramResourceLocation\");\n\tglad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load(\"glUseProgramStages\");\n\tglad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load(\"glActiveShaderProgram\");\n\tglad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load(\"glCreateShaderProgramv\");\n\tglad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load(\"glBindProgramPipeline\");\n\tglad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load(\"glDeleteProgramPipelines\");\n\tglad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load(\"glGenProgramPipelines\");\n\tglad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load(\"glIsProgramPipeline\");\n\tglad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load(\"glGetProgramPipelineiv\");\n\tglad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load(\"glProgramUniform1i\");\n\tglad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load(\"glProgramUniform2i\");\n\tglad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load(\"glProgramUniform3i\");\n\tglad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load(\"glProgramUniform4i\");\n\tglad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load(\"glProgramUniform1ui\");\n\tglad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load(\"glProgramUniform2ui\");\n\tglad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load(\"glProgramUniform3ui\");\n\tglad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load(\"glProgramUniform4ui\");\n\tglad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load(\"glProgramUniform1f\");\n\tglad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load(\"glProgramUniform2f\");\n\tglad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load(\"glProgramUniform3f\");\n\tglad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load(\"glProgramUniform4f\");\n\tglad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load(\"glProgramUniform1iv\");\n\tglad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load(\"glProgramUniform2iv\");\n\tglad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load(\"glProgramUniform3iv\");\n\tglad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load(\"glProgramUniform4iv\");\n\tglad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load(\"glProgramUniform1uiv\");\n\tglad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load(\"glProgramUniform2uiv\");\n\tglad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load(\"glProgramUniform3uiv\");\n\tglad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load(\"glProgramUniform4uiv\");\n\tglad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load(\"glProgramUniform1fv\");\n\tglad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load(\"glProgramUniform2fv\");\n\tglad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load(\"glProgramUniform3fv\");\n\tglad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load(\"glProgramUniform4fv\");\n\tglad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load(\"glProgramUniformMatrix2fv\");\n\tglad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load(\"glProgramUniformMatrix3fv\");\n\tglad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load(\"glProgramUniformMatrix4fv\");\n\tglad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load(\"glProgramUniformMatrix2x3fv\");\n\tglad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load(\"glProgramUniformMatrix3x2fv\");\n\tglad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load(\"glProgramUniformMatrix2x4fv\");\n\tglad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load(\"glProgramUniformMatrix4x2fv\");\n\tglad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load(\"glProgramUniformMatrix3x4fv\");\n\tglad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load(\"glProgramUniformMatrix4x3fv\");\n\tglad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load(\"glValidateProgramPipeline\");\n\tglad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load(\"glGetProgramPipelineInfoLog\");\n\tglad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load(\"glBindImageTexture\");\n\tglad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load(\"glGetBooleani_v\");\n\tglad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load(\"glMemoryBarrier\");\n\tglad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)load(\"glMemoryBarrierByRegion\");\n\tglad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load(\"glTexStorage2DMultisample\");\n\tglad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load(\"glGetMultisamplefv\");\n\tglad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load(\"glSampleMaski\");\n\tglad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load(\"glGetTexLevelParameteriv\");\n\tglad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load(\"glGetTexLevelParameterfv\");\n\tglad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load(\"glBindVertexBuffer\");\n\tglad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load(\"glVertexAttribFormat\");\n\tglad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load(\"glVertexAttribIFormat\");\n\tglad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load(\"glVertexAttribBinding\");\n\tglad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load(\"glVertexBindingDivisor\");\n}\nstatic void load_GL_ES_VERSION_3_2(GLADloadproc load) {\n\tif(!GLAD_GL_ES_VERSION_3_2) return;\n\tglad_glBlendBarrier = (PFNGLBLENDBARRIERPROC)load(\"glBlendBarrier\");\n\tglad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load(\"glCopyImageSubData\");\n\tglad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load(\"glDebugMessageControl\");\n\tglad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load(\"glDebugMessageInsert\");\n\tglad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load(\"glDebugMessageCallback\");\n\tglad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load(\"glGetDebugMessageLog\");\n\tglad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load(\"glPushDebugGroup\");\n\tglad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load(\"glPopDebugGroup\");\n\tglad_glObjectLabel = (PFNGLOBJECTLABELPROC)load(\"glObjectLabel\");\n\tglad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load(\"glGetObjectLabel\");\n\tglad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load(\"glObjectPtrLabel\");\n\tglad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load(\"glGetObjectPtrLabel\");\n\tglad_glGetPointerv = (PFNGLGETPOINTERVPROC)load(\"glGetPointerv\");\n\tglad_glEnablei = (PFNGLENABLEIPROC)load(\"glEnablei\");\n\tglad_glDisablei = (PFNGLDISABLEIPROC)load(\"glDisablei\");\n\tglad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load(\"glBlendEquationi\");\n\tglad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load(\"glBlendEquationSeparatei\");\n\tglad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load(\"glBlendFunci\");\n\tglad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load(\"glBlendFuncSeparatei\");\n\tglad_glColorMaski = (PFNGLCOLORMASKIPROC)load(\"glColorMaski\");\n\tglad_glIsEnabledi = (PFNGLISENABLEDIPROC)load(\"glIsEnabledi\");\n\tglad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load(\"glDrawElementsBaseVertex\");\n\tglad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load(\"glDrawRangeElementsBaseVertex\");\n\tglad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load(\"glDrawElementsInstancedBaseVertex\");\n\tglad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load(\"glFramebufferTexture\");\n\tglad_glPrimitiveBoundingBox = (PFNGLPRIMITIVEBOUNDINGBOXPROC)load(\"glPrimitiveBoundingBox\");\n\tglad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)load(\"glGetGraphicsResetStatus\");\n\tglad_glReadnPixels = (PFNGLREADNPIXELSPROC)load(\"glReadnPixels\");\n\tglad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)load(\"glGetnUniformfv\");\n\tglad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)load(\"glGetnUniformiv\");\n\tglad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)load(\"glGetnUniformuiv\");\n\tglad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load(\"glMinSampleShading\");\n\tglad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load(\"glPatchParameteri\");\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_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load(\"glSamplerParameterIiv\");\n\tglad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load(\"glSamplerParameterIuiv\");\n\tglad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load(\"glGetSamplerParameterIiv\");\n\tglad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load(\"glGetSamplerParameterIuiv\");\n\tglad_glTexBuffer = (PFNGLTEXBUFFERPROC)load(\"glTexBuffer\");\n\tglad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load(\"glTexBufferRange\");\n\tglad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load(\"glTexStorage3DMultisample\");\n}\nstatic void load_GL_EXT_clip_control(GLADloadproc load) {\n\tif(!GLAD_GL_EXT_clip_control) return;\n\tglad_glClipControlEXT = (PFNGLCLIPCONTROLEXTPROC)load(\"glClipControlEXT\");\n}\nstatic int find_extensionsGLES2(void) {\n\tif (!get_exts()) return 0;\n\tGLAD_GL_EXT_clip_control = has_ext(\"GL_EXT_clip_control\");\n\tfree_exts();\n\treturn 1;\n}\n\nstatic void find_coreGLES2(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_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;\n\tGLAD_GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;\n\tGLAD_GL_ES_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;\n\tGLAD_GL_ES_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;\n\tif (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 2)) {\n\t\tmax_loaded_major = 3;\n\t\tmax_loaded_minor = 2;\n\t}\n}\n\nint gladLoadGLES2Loader(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_coreGLES2();\n\tload_GL_ES_VERSION_2_0(load);\n\tload_GL_ES_VERSION_3_0(load);\n\tload_GL_ES_VERSION_3_1(load);\n\tload_GL_ES_VERSION_3_2(load);\n\n\tif (!find_extensionsGLES2()) return 0;\n\tload_GL_EXT_clip_control(load);\n\treturn GLVersion.major != 0 || GLVersion.minor != 0;\n}\n\n"
  },
  {
    "path": "src/gl/inject_egl.cpp",
    "content": "#include <iostream>\n#include <array>\n#include <unordered_map>\n#include <cstring>\n#include <dlfcn.h>\n#include <chrono>\n#include <iomanip>\n#include <spdlog/spdlog.h>\n#include \"real_dlsym.h\"\n#include \"mesa/util/macros.h\"\n#include \"mesa/util/os_time.h\"\n#include \"blacklist.h\"\n#include \"gl_hud.h\"\n#include \"elfhacks.h\"\n#ifdef HAVE_WAYLAND\n#include \"wayland_hook.h\"\n#endif\n#include \"../fps_limiter.h\"\n\nusing namespace MangoHud::GL;\n\n#ifndef EGL_WIDTH\n#define EGL_HEIGHT  0x3056\n#define EGL_WIDTH   0x3057\n#define EGL_DRAW    0x3059\n#define EGL_READ    0x305A\n#endif\n\n#define EGL_PLATFORM_WAYLAND_KHR          0x31D8\n\n// single global lock, for simplicity\nstatic std::mutex global_lock;\ntypedef std::lock_guard<std::mutex> scoped_lock;\nstatic std::unordered_map<void *, gl_context *> gl_contexts;\n\nEXPORT_C_(void *) eglGetProcAddress(const char* procName);\n\nstatic void* get_egl_proc_address(const char* name) {\n\n    void *func = nullptr;\n    static void *(*pfn_eglGetProcAddress)(const char*) = nullptr;\n    const char *libs[] = {\n        \"*libEGL.so.*\",\n        \"*libEGL_mesa.so.*\",\n        \"*libEGL_nvidia.so.*\"\n    };\n\n    if (!pfn_eglGetProcAddress) {\n        eh_obj_t lib_egl;\n        int ret;\n\n        for (uint i = 0; i < sizeof(libs)/sizeof(*libs); i++)\n        {\n            ret = eh_find_obj(&lib_egl, libs[i]);\n\n            if (ret) continue;\n\n            eh_find_sym(&lib_egl, \"eglGetProcAddress\", (void **)&pfn_eglGetProcAddress);\n            eh_destroy_obj(&lib_egl);\n\n            if (pfn_eglGetProcAddress) break;\n        }\n    }\n\n    if (pfn_eglGetProcAddress)\n        func = pfn_eglGetProcAddress(name);\n\n    if (!func)\n        func = get_proc_address( name );\n\n    if (!func) {\n        SPDLOG_ERROR(\"Failed to get function '{}'\", name);\n    }\n\n    return func;\n}\n\nstatic gl_context *create_gl_context(void *ctx)\n{\n    gl_context *gl_ctx;\n\n    gl_ctx = (gl_context *)calloc(1, sizeof(*gl_ctx));\n    gl_ctx->ctx = ctx;\n    gl_contexts[ctx] = gl_ctx;\n    //SPDLOG_DEBUG(\"created gl_context {} for GLX context {}\", (void *)gl_ctx, ctx);\n    return gl_ctx;\n}\n\nstatic void destroy_gl_context(gl_context *gl_ctx)\n{\n    //SPDLOG_DEBUG(\"destroying gl_context {} for GLX context {}\", (void *)gl_ctx, gl_ctx->ctx);\n    gl_contexts.erase(gl_ctx->ctx);\n    free(gl_ctx);\n}\n\nEXPORT_C_(unsigned int) eglDestroyContext(void* dpy, void* ctx);\nEXPORT_C_(unsigned int) eglDestroyContext(void* dpy, void* ctx)\n{\n    static unsigned int (*pfn_eglDestroyContext)(void* dpy, void* ctx) = nullptr;\n    ::scoped_lock lk(global_lock);\n    gl_context *gl_ctx = gl_contexts[ctx];\n    void *current_ctx, *draw, *read = nullptr;\n    int r;\n\n    if (!pfn_eglDestroyContext)\n        pfn_eglDestroyContext = reinterpret_cast<decltype(pfn_eglDestroyContext)>(get_egl_proc_address(\"eglDestroyContext\"));\n\n    if (gl_ctx)\n    {\n        static void* (*pfn_eglGetCurrentContext)() = nullptr;\n        if (!pfn_eglGetCurrentContext)\n            pfn_eglGetCurrentContext = reinterpret_cast<decltype(pfn_eglGetCurrentContext)>(get_egl_proc_address(\"eglGetCurrentContext\"));\n        static void* (*pfn_eglGetCurrentSurface)(int readdraw) = nullptr;\n        if (!pfn_eglGetCurrentSurface)\n            pfn_eglGetCurrentSurface = reinterpret_cast<decltype(pfn_eglGetCurrentSurface)>(get_egl_proc_address(\"eglGetCurrentSurface\"));\n        static unsigned int (*pfn_eglMakeCurrent)(void* dpy, void* draw, void* read, void* ctx) = nullptr;\n        if (!pfn_eglMakeCurrent)\n            pfn_eglMakeCurrent = reinterpret_cast<decltype(pfn_eglMakeCurrent)>(get_egl_proc_address(\"eglMakeCurrent\"));\n\n        current_ctx = pfn_eglGetCurrentContext();\n        draw = pfn_eglGetCurrentSurface(EGL_DRAW);\n        read = pfn_eglGetCurrentSurface(EGL_READ);\n        //SPDLOG_DEBUG(\"gl_context {}, current_ctx {}, draw {}, read {}\", (void *)gl_ctx, current_ctx, draw, read);\n        r = pfn_eglMakeCurrent(dpy, draw, read, ctx);\n        if (r)\n        {\n            imgui_shutdown(gl_ctx, gl_contexts.size() == 1);\n            pfn_eglMakeCurrent(dpy, draw, read, current_ctx);\n        }\n        destroy_gl_context(gl_ctx);\n    }\n    return pfn_eglDestroyContext(dpy, ctx);\n}\n\nEXPORT_C_(unsigned int) eglSwapBuffers(void* dpy, void* surf);\nEXPORT_C_(unsigned int) eglSwapBuffers(void* dpy, void* surf)\n{\n    static int (*pfn_eglSwapBuffers)(void*, void*) = nullptr;\n    if (!pfn_eglSwapBuffers)\n        pfn_eglSwapBuffers = reinterpret_cast<decltype(pfn_eglSwapBuffers)>(get_egl_proc_address(\"eglSwapBuffers\"));\n\n    if (!is_blacklisted()) {\n        static int (*pfn_eglQuerySurface)(void* dpy, void* surface, int attribute, int *value) = nullptr;\n        if (!pfn_eglQuerySurface)\n            pfn_eglQuerySurface = reinterpret_cast<decltype(pfn_eglQuerySurface)>(get_egl_proc_address(\"eglQuerySurface\"));\n        static void* (*pfn_eglGetCurrentContext)() = nullptr;\n        if (!pfn_eglGetCurrentContext)\n            pfn_eglGetCurrentContext = reinterpret_cast<decltype(pfn_eglGetCurrentContext)>(get_egl_proc_address(\"eglGetCurrentContext\"));\n        ::scoped_lock lk(global_lock);\n        void* ctx = pfn_eglGetCurrentContext();\n        gl_context *gl_ctx = gl_contexts[ctx];\n\n        if (!gl_ctx)\n            gl_ctx = create_gl_context(ctx);\n        imgui_create(gl_ctx, gl_wsi::GL_WSI_EGL);\n\n        int width=0, height=0;\n        if (pfn_eglQuerySurface(dpy, surf, EGL_HEIGHT, &height) &&\n            pfn_eglQuerySurface(dpy, surf, EGL_WIDTH, &width))\n            imgui_render(gl_ctx, width, height);\n\n        if (fps_limiter)\n            fps_limiter->limit(true);\n    }\n\n    int res = pfn_eglSwapBuffers(dpy, surf);\n\n    if (!is_blacklisted()) {\n        if (fps_limiter)\n            fps_limiter->limit(false);\n    }\n\n    return res;\n}\n\nEXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_display, const intptr_t* attrib_list);\nEXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_display, const intptr_t* attrib_list)\n{\n    void *ret;\n    static void* (*pfn_eglGetPlatformDisplay)(unsigned int, void*, const intptr_t*) = nullptr;\n\n    if (!pfn_eglGetPlatformDisplay)\n        pfn_eglGetPlatformDisplay = reinterpret_cast<decltype(pfn_eglGetPlatformDisplay)>(get_egl_proc_address(\"eglGetPlatformDisplay\"));\n\n    ret = pfn_eglGetPlatformDisplay(platform, native_display, attrib_list);\n\n#ifdef HAVE_WAYLAND\n    if (platform == EGL_PLATFORM_WAYLAND_KHR && ret)\n    {\n        HUDElements.display_server = HUDElements.display_servers::WAYLAND;\n        init_wayland_data((struct wl_display*)native_display, ret);\n    }\n#endif\n\n    return ret;\n}\n\nEXPORT_C_(void*) eglGetDisplay( void* native_display );\nEXPORT_C_(void*) eglGetDisplay( void* native_display )\n{\n    void *ret;\n    static void* (*pfn_eglGetDisplay)(void*) = nullptr;\n\n    if (!pfn_eglGetDisplay)\n        pfn_eglGetDisplay = reinterpret_cast<decltype(pfn_eglGetDisplay)>(get_egl_proc_address(\"eglGetDisplay\"));\n\n    ret = pfn_eglGetDisplay(native_display);\n\n#ifdef HAVE_WAYLAND\n    try\n    {\n        void** display_ptr = (void**)native_display;\n        if (native_display && ret)\n        {\n            wl_interface* iface = (wl_interface*)*display_ptr;\n            if (iface && strcmp(iface->name, wl_display_interface.name) == 0)\n            {\n                HUDElements.display_server = HUDElements.display_servers::WAYLAND;\n                init_wayland_data((struct wl_display*)native_display, ret);\n            }\n        }\n    }\n    catch(...)\n    {\n    }\n#endif\n\n    return ret;\n}\n\nEXPORT_C_(int) eglTerminate(void *display);\nEXPORT_C_(int) eglTerminate(void *display)\n{\n    int ret;\n    static int (*pfn_eglTerminate)(void*) = nullptr;\n\n    if (!pfn_eglTerminate)\n        pfn_eglTerminate = reinterpret_cast<decltype(pfn_eglTerminate)>(get_egl_proc_address(\"eglTerminate\"));\n\n    ret = pfn_eglTerminate(display);\n\n#ifdef HAVE_WAYLAND\n    if (ret)\n    {\n        wayland_data_unref(NULL, display);\n    }\n#endif\n\n    return ret;\n}\n\nstruct func_ptr {\n   const char *name;\n   void *ptr;\n};\n\nstatic std::array<const func_ptr, 6> name_to_funcptr_map = {{\n#define ADD_HOOK(fn) { #fn, (void *) fn }\n    ADD_HOOK(eglDestroyContext),\n    ADD_HOOK(eglGetDisplay),\n    ADD_HOOK(eglGetPlatformDisplay),\n    ADD_HOOK(eglGetProcAddress),\n    ADD_HOOK(eglSwapBuffers),\n    ADD_HOOK(eglTerminate)\n#undef ADD_HOOK\n}};\n\nEXPORT_C_(void *) mangohud_find_egl_ptr(const char *name);\nEXPORT_C_(void *) mangohud_find_egl_ptr(const char *name)\n{\n  if (is_blacklisted())\n      return nullptr;\n\n   for (auto& func : name_to_funcptr_map) {\n      if (strcmp(name, func.name) == 0)\n         return func.ptr;\n   }\n\n   return nullptr;\n}\n\nEXPORT_C_(void *) eglGetProcAddress(const char* procName) {\n    void* real_func = get_egl_proc_address(procName);\n    void* func = mangohud_find_egl_ptr(procName);\n    SPDLOG_TRACE(\"{}: proc: {}, real: {}, fun: {}\", __func__, procName, real_func, func);\n    if (func && real_func)\n        return func;\n\n    return real_func;\n}\n"
  },
  {
    "path": "src/gl/inject_glx.cpp",
    "content": "#include <X11/Xlib.h>\n#include <iostream>\n#include <array>\n#include <thread>\n#include <vector>\n#include <unordered_map>\n#include <algorithm>\n#include <atomic>\n#include <cstring>\n#include <spdlog/spdlog.h>\n#include \"real_dlsym.h\"\n#include \"loaders/loader_glx.h\"\n#include \"loaders/loader_x11.h\"\n#include \"mesa/util/macros.h\"\n#include \"mesa/util/os_time.h\"\n#include \"blacklist.h\"\n\n#include <chrono>\n#include <iomanip>\n\n#include <glad/glad.h>\n#include \"gl_hud.h\"\n#include \"../config.h\"\n#include \"../fps_limiter.h\"\n\nusing namespace MangoHud::GL;\n\n#ifndef GLX_WIDTH\n#define GLX_WIDTH   0x801D\n#define GLX_HEIGHT  0x801E\n#endif\n\nstatic glx_loader glx;\n\n// single global lock, for simplicity\nstatic std::mutex global_lock;\ntypedef std::lock_guard<std::mutex> scoped_lock;\nstatic std::unordered_map<void *, gl_context *> gl_contexts;\n\nstatic void* get_glx_proc_address(const char* name) {\n    glx.Load();\n\n    void *func = nullptr;\n    if (glx.GetProcAddress)\n        func = glx.GetProcAddress( (const unsigned char*) name );\n\n    if (!func && glx.GetProcAddressARB)\n        func = glx.GetProcAddressARB( (const unsigned char*) name );\n\n    if (!func)\n        func = get_proc_address( name );\n\n    if (!func) {\n        SPDLOG_ERROR(\"Failed to get function '{}'\", name);\n    }\n\n    return func;\n}\n\nbool glx_mesa_queryInteger(int attrib, unsigned int *value);\nbool glx_mesa_queryInteger(int attrib, unsigned int *value)\n{\n    static int (*pfn_queryInteger)(int attribute, unsigned int *value) =\n        reinterpret_cast<decltype(pfn_queryInteger)>(get_glx_proc_address(\n                    \"glXQueryCurrentRendererIntegerMESA\"));\n    if (pfn_queryInteger)\n        return !!pfn_queryInteger(attrib, value);\n    return false;\n}\n\nstatic gl_context *create_gl_context(void *ctx)\n{\n    gl_context *gl_ctx;\n\n    gl_ctx = (gl_context *)calloc(1, sizeof(*gl_ctx));\n    gl_ctx->ctx = ctx;\n    gl_contexts[ctx] = gl_ctx;\n    //SPDLOG_DEBUG(\"created gl_context {} for GLX context {}\", (void *)gl_ctx, ctx);\n    return gl_ctx;\n}\n\nstatic void destroy_gl_context(gl_context *gl_ctx)\n{\n    //SPDLOG_DEBUG(\"destroying gl_context {} for GLX context {}\", (void *)gl_ctx, gl_ctx->ctx);\n    gl_contexts.erase(gl_ctx->ctx);\n    free(gl_ctx);\n}\n\nEXPORT_C_(void) glXDestroyContext(void *dpy, void *ctx)\n{\n    ::scoped_lock lk(global_lock);\n    gl_context *gl_ctx = gl_contexts[ctx];\n    void *current_ctx, *draw, *read = nullptr;\n    int r;\n\n    SPDLOG_DEBUG(\"{}: {}\", __func__, ctx);\n    glx.Load();\n\n    if (gl_ctx)\n    {\n        current_ctx = glx.GetCurrentContext();\n        draw = glx.GetCurrentDrawable();\n        if (glx.GetCurrentReadDrawable)\n            read = glx.GetCurrentReadDrawable();\n        //SPDLOG_DEBUG(\"gl_context {}, current_ctx {}, draw {}, read {}\", (void *)gl_ctx, current_ctx, draw, read);\n        if (glx.MakeContextCurrent)\n            r = glx.MakeContextCurrent(dpy, draw, read, ctx);\n        else\n            r = glx.MakeCurrent(dpy, draw, ctx);\n        if (r)\n        {\n            imgui_shutdown(gl_ctx, gl_contexts.size() == 1);\n            if (glx.MakeContextCurrent)\n                glx.MakeContextCurrent(dpy, draw, read, current_ctx);\n            else\n                glx.MakeCurrent(dpy, draw, current_ctx);\n        }\n        destroy_gl_context(gl_ctx);\n    }\n\n    glx.DestroyContext(dpy, ctx);\n}\n\n#ifndef GLX_SWAP_INTERVAL_EXT\n#define GLX_SWAP_INTERVAL_EXT 0x20F1\n#endif\n\nstatic void do_imgui_swap(void *dpy, void *drawable)\n{\n    static auto last_time = std::chrono::steady_clock::now();\n    auto current_time = std::chrono::steady_clock::now();\n\n    // if bufferSize is 0 then glXQueryDrawable is probably not working\n    // this is the case with llvmpipe\n    unsigned int bufferSize;\n    glx.QueryDrawable(dpy, drawable, GL_BUFFER_SIZE, &bufferSize);\n\n    std::chrono::duration<double> elapsed_seconds = current_time - last_time;\n    if (bufferSize != 0 && (HUDElements.vsync == 10 || elapsed_seconds.count() > 5.0))\n        glx.QueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &HUDElements.vsync);\n\n    GLint vp[4];\n    if (!is_blacklisted()) {\n        ::scoped_lock lk(global_lock);\n        void *ctx = glx.GetCurrentContext();\n        gl_context *gl_ctx = gl_contexts[ctx];\n\n        //SPDLOG_TRACE(\"ctx {}, gl_ctx {}\", ctx, (void *)gl_ctx);\n        if (!gl_ctx)\n            gl_ctx = create_gl_context(ctx);\n        imgui_create(gl_ctx, gl_wsi::GL_WSI_GLX);\n\n        unsigned int width = -1, height = -1;\n\n        switch (get_params()->gl_size_query)\n        {\n            case GL_SIZE_VIEWPORT:\n                glGetIntegerv (GL_VIEWPORT, vp);\n                width = vp[2];\n                height = vp[3];\n                break;\n            case GL_SIZE_SCISSORBOX:\n                glGetIntegerv (GL_SCISSOR_BOX, vp);\n                width = vp[2];\n                height = vp[3];\n                break;\n            default:\n                glx.QueryDrawable(dpy, drawable, GLX_WIDTH, &width);\n                glx.QueryDrawable(dpy, drawable, GLX_HEIGHT, &height);\n                break;\n        }\n\n        SPDLOG_TRACE(\"swap buffers: {}x{}\", width, height);\n        imgui_render(gl_ctx, width, height);\n    }\n}\n\nstatic void set_swap_interval(void* dpy, void* drawable, int interval)\n{\n    ::scoped_lock lk(global_lock);\n    void* ctx = glx.GetCurrentContext();\n    gl_context *gl_ctx = gl_contexts[ctx];\n\n    if (!is_blacklisted() || interval >= 0)\n    {\n        std::shared_ptr<overlay_params> real_params;\n\n        if (gl_ctx)\n        {\n            if (gl_ctx->swap_interval_set && interval < -1)\n                return;\n\n            if (!is_blacklisted())\n            {\n                imgui_create(gl_ctx, gl_wsi::GL_WSI_GLX);\n\n                real_params = get_params();\n            }\n        }\n\n        // Disabled: -1 is outside of the GLX_SWAP_INTERVAL_EXT spec and will crash with BadValue in Zink.\n        // Original code kept for reference:\n        // if (glx.SwapIntervalEXT && ((real_params && real_params->gl_vsync >= -1) || (interval >= -1 && dpy && drawable)))\n        // {\n        //     glx.SwapIntervalEXT(dpy, drawable, real_params && real_params->gl_vsync >= -1 ? real_params->gl_vsync : interval);\n        // }\n        if ((real_params && real_params->gl_vsync >= 0) || interval >= 0)\n        {\n            if (glx.SwapIntervalSGI)\n                glx.SwapIntervalSGI(real_params && real_params->gl_vsync >= 0 ? real_params->gl_vsync : interval);\n            if (glx.SwapIntervalMESA)\n                glx.SwapIntervalMESA(real_params && real_params->gl_vsync >= 0 ? real_params->gl_vsync : interval);\n        }\n        if (gl_ctx)\n            gl_ctx->swap_interval_set = true;\n    }\n}\n\nEXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) {\n    glx.Load();\n    SPDLOG_TRACE(\"{}: {}\", __func__, drawable);\n\n    do_imgui_swap(dpy, drawable);\n    set_swap_interval(dpy, drawable, -2);\n    if (fps_limiter)\n        fps_limiter->limit(true);\n\n    glx.SwapBuffers(dpy, drawable);\n    if (!is_blacklisted())\n        if (fps_limiter)\n            fps_limiter->limit(false);\n}\n\nEXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder)\n{\n    glx.Load();\n    SPDLOG_DEBUG(\"{}: {}, {}, {}, {}\", __func__, drawable, target_msc, divisor, remainder);\n    if (!glx.SwapBuffersMscOML)\n        return -1;\n\n    do_imgui_swap(dpy, drawable);\n    set_swap_interval(dpy, drawable, -2);\n    if (fps_limiter)\n        fps_limiter->limit(true);\n\n    int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder);\n\n    if (!is_blacklisted())\n        if (fps_limiter)\n            fps_limiter->limit(true);\n\n    return ret;\n}\n\nEXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) {\n    SPDLOG_DEBUG(\"{}: {}, {}\", __func__, draw, interval);\n    glx.Load();\n    if (!glx.SwapIntervalEXT)\n        return;\n\n    set_swap_interval(dpy, draw, interval);\n}\n\nEXPORT_C_(int) glXSwapIntervalSGI(int interval) {\n    SPDLOG_DEBUG(\"{}: {}\", __func__, interval);\n    glx.Load();\n    if (!glx.SwapIntervalSGI)\n        return -1;\n\n    set_swap_interval(nullptr, nullptr, interval);\n    return 0;\n}\n\nEXPORT_C_(int) glXSwapIntervalMESA(unsigned int interval) {\n    SPDLOG_DEBUG(\"{}: {}\", __func__, interval);\n    glx.Load();\n    if (!glx.SwapIntervalMESA)\n        return -1;\n\n    set_swap_interval(nullptr, nullptr, interval);\n    return 0;\n}\n\nEXPORT_C_(int) glXGetSwapIntervalMESA() {\n    glx.Load();\n    if (!glx.GetSwapIntervalMESA)\n        return 0;\n\n    int interval = glx.GetSwapIntervalMESA();\n\n    if (!is_blacklisted()) {\n        static bool first_call = true;\n\n        if (first_call) {\n            first_call = false;\n            if (get_params()->gl_vsync >= 0) {\n                interval = get_params()->gl_vsync;\n                glx.SwapIntervalMESA(interval);\n            }\n        }\n    }\n\n    SPDLOG_DEBUG(\"{}: {}\", __func__, interval);\n    return interval;\n}\n\nstruct func_ptr {\n   const char *name;\n   void *ptr;\n};\n\nstatic std::array<const func_ptr, 9> name_to_funcptr_map = {{\n#define ADD_HOOK(fn) { #fn, (void *) fn }\n   ADD_HOOK(glXGetProcAddress),\n   ADD_HOOK(glXGetProcAddressARB),\n   ADD_HOOK(glXDestroyContext),\n   ADD_HOOK(glXSwapBuffers),\n   ADD_HOOK(glXSwapBuffersMscOML),\n\n   ADD_HOOK(glXSwapIntervalEXT),\n   ADD_HOOK(glXSwapIntervalSGI),\n   ADD_HOOK(glXSwapIntervalMESA),\n   ADD_HOOK(glXGetSwapIntervalMESA),\n#undef ADD_HOOK\n}};\n\nEXPORT_C_(void *) mangohud_find_glx_ptr(const char *name);\nEXPORT_C_(void *) mangohud_find_glx_ptr(const char *name)\n{\n  if (is_blacklisted())\n      return nullptr;\n\n   for (auto& func : name_to_funcptr_map) {\n      if (strcmp(name, func.name) == 0)\n         return func.ptr;\n   }\n\n   return nullptr;\n}\n\nEXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {\n    void *real_func = get_glx_proc_address((const char*)procName);\n    void *func = mangohud_find_glx_ptr( (const char*)procName );\n    SPDLOG_TRACE(\"{}: '{}', real: {}, fun: {}\", __func__, reinterpret_cast<const char*>(procName), real_func, func);\n\n    if (func && real_func)\n        return func;\n\n    return real_func;\n}\n\nEXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {\n    void *real_func = get_glx_proc_address((const char*)procName);\n    void *func = mangohud_find_glx_ptr( (const char*)procName );\n    SPDLOG_TRACE(\"{}: '{}', real: {}, fun: {}\", __func__, reinterpret_cast<const char*>(procName), real_func, func);\n    if (func && real_func)\n        return func;\n\n    return real_func;\n}\n"
  },
  {
    "path": "src/gl/shim.c",
    "content": "#include <dlfcn.h>\n#include <errno.h>\n#include <link.h>\n#include <stdio.h>\n#include <stdint.h>\n#include \"gl.h\"\n#include \"real_dlsym.h\"\n#include <string.h>\n#include <stdbool.h>\n#include <stdlib.h>\n\n#ifndef RTLD_DEEPBIND\n#define RTLD_DEEPBIND 0\n#endif\n\nstatic void* handle = NULL;\nstatic bool mangoHudLoaded = false;\n\n#ifdef __GLIBC__\nstatic inline void\nfree_indirect(char **p)\n{\n    free(*p);\n}\n\nstatic bool load_adjacent_opengl_lib(void)\n{\n    __attribute__((cleanup(free_indirect))) char *location = NULL;\n    __attribute__((cleanup(free_indirect))) char *lib = NULL;\n    Dl_info info = {};\n    void *extra_info = NULL;\n\n    // The first argument can be any symbol in this shared library,\n    // mangoHudLoaded is a convenient one\n    if (!dladdr1(&mangoHudLoaded, &info, &extra_info, RTLD_DL_LINKMAP))\n    {\n        fprintf(stderr, \"shim: Unable to find my own location: %s\\n\", dlerror());\n        return false;\n    }\n\n    const struct link_map *map = extra_info;\n    if (map == NULL)\n    {\n        fprintf(stderr, \"shim: Unable to find my own location: NULL link_map\\n\");\n        return false;\n    }\n    if (map->l_name == NULL)\n    {\n        fprintf(stderr, \"shim: Unable to find my own location: NULL l_name\\n\");\n        return false;\n    }\n\n    location = realpath(map->l_name, NULL);\n    char *slash = strrchr(location, '/');\n\n    if (slash == NULL)\n    {\n        fprintf(stderr, \"shim: Unable to find my own location: no directory separator\\n\");\n        return false;\n    }\n\n    *slash = '\\0';\n\n    if (asprintf(&lib, \"%s/libMangoHud_opengl.so\", location) < 0)\n    {\n        fprintf(stderr, \"shim: asprintf: %s\\n\", strerror(errno));\n        return false;\n    }\n\n    handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);\n\n    if (handle == NULL)\n    {\n        fprintf(stderr, \"shim: Failed to load from \\\"%s\\\": %s\\n\", lib, dlerror());\n        return false;\n    }\n\n    return true;\n}\n#endif\n\n// Load MangoHud after EGL/GLX functions have been intercepted\nstatic void loadMangoHud(void);\nstatic void loadMangoHud() {\n    if (mangoHudLoaded) return;\n\n    // allow user to load custom mangohud libs (useful for testing)\n    char *libs = getenv(\"MANGOHUD_OPENGL_LIBS\");\n    char *lib = NULL;\n\n    if (libs)\n    {\n        lib = strtok(libs, \":\");\n\n        // when user specifies only one path\n        if (!lib) lib = libs;\n\n        while (lib != NULL)\n        {\n            handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);\n\n            if (handle)\n            {\n                mangoHudLoaded = true;\n                return;\n            }\n            else fprintf(stderr, \"shim: Failed to load from \\\"%s\\\": %s\\n\", lib, dlerror());\n\n            lib = strtok(NULL, \":\");\n        }\n    }\n\n#ifdef __GLIBC__\n    if (load_adjacent_opengl_lib())\n    {\n        mangoHudLoaded = true;\n        return;\n    }\n#endif\n\n    if (!mangoHudLoaded)\n    {\n        handle = dlopen(\"${ORIGIN}/libMangoHud_opengl.so\", RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);\n        if (handle) mangoHudLoaded = true;\n        else\n        {\n            fprintf(stderr, \"shim: Failed to load from ${ORIGIN}/libMangoHud_opengl.so: %s\\n\", dlerror());\n            handle = RTLD_NEXT;\n        }\n    }\n}\n\n#define CREATE_FWD_VOID(name, params, ...) \\\n    void name params { \\\n        loadMangoHud(); \\\n        void (*p##name) params = real_dlsym(handle, #name); \\\n        if (p##name) p##name(__VA_ARGS__); \\\n    }\n#define CREATE_FWD(ret_type, name, params, ...) \\\n    ret_type name params { \\\n        loadMangoHud(); \\\n        ret_type (*p##name) params = real_dlsym(handle, #name); \\\n        if (p##name) return p##name(__VA_ARGS__); \\\n        return (ret_type)0; \\\n    }\n\n#ifdef HAVE_X11\nCREATE_FWD_VOID(glXSwapBuffers, (void* dpy, void* drawable), dpy, drawable)\nCREATE_FWD(int64_t, glXSwapBuffersMscOML,\n           (void* dpy, void* drawable, int64_t target_msc,\n            int64_t divisor, int64_t remainder),\n           dpy, drawable, target_msc, divisor, remainder)\nCREATE_FWD_VOID(glXDestroyContext, (void *dpy, void *ctx), dpy, ctx)\nCREATE_FWD(void*, glXGetProcAddress, (const unsigned char* procName), procName)\nCREATE_FWD(void*, glXGetProcAddressARB, (const unsigned char* procName), procName)\n#endif\nCREATE_FWD(void*, eglGetDisplay, (void* native_dpy), native_dpy)\nCREATE_FWD(void*, eglGetPlatformDisplay,\n    (unsigned int platform,\n     void* native_display,\n     const intptr_t* attrib_list),\n     platform, native_display, attrib_list)\nCREATE_FWD(unsigned int, eglSwapBuffers, (void* dpy, void* surf), dpy, surf)\nCREATE_FWD(void*, eglGetProcAddress, (const char* procName), procName)\nCREATE_FWD(int, eglTerminate, (void *display), display)\nCREATE_FWD(unsigned int, eglDestroyContext, (void *dpy, void *ctx), dpy, ctx)\n\n#undef CREATE_FWD\n#undef CREATE_FWD_VOID\n\nstruct func_ptr {\n    const char* name;\n    void* ptr;\n};\n\n#define ADD_HOOK(fn) { #fn, (void*)fn }\nstatic struct func_ptr hooks[] = {\n#ifdef HAVE_X11\n    ADD_HOOK(glXGetProcAddress),\n    ADD_HOOK(glXGetProcAddressARB),\n    ADD_HOOK(glXDestroyContext),\n    ADD_HOOK(glXSwapBuffers),\n    ADD_HOOK(glXSwapBuffersMscOML),\n#endif\n    ADD_HOOK(eglDestroyContext),\n    ADD_HOOK(eglSwapBuffers),\n    ADD_HOOK(eglGetPlatformDisplay),\n    ADD_HOOK(eglGetDisplay),\n    ADD_HOOK(eglGetProcAddress),\n    ADD_HOOK(eglTerminate)\n};\n#undef ADD_HOOK\n\n#ifndef ARRAY_SIZE\n#define ARRAY_SIZE(arr) sizeof(arr)/sizeof(arr[0])\n#endif\n\n#include <stddef.h>\n\n// Glibc has nonconformance behaviour\n// which is Glibc clears dlerror if dlsym succeded instead\n// leaving it as it is as required by standard\n// Reference: https://pubs.opengroup.org/onlinepubs/009604299/functions/dlsym.html\n//\n// Lets disable dlerror override to avoid risking programs\n// which already relying on Glibc's behaviour so to keep\n// glibc's behaviour\n// while on conformance system such as Musl it fixes bugs\n#ifdef __GLIBC__\n# define USE_DLERROR_OVERRIDE 0\n#else\n# define USE_DLERROR_OVERRIDE 1\n#endif\n\nstatic _Thread_local char *error_override = NULL;\nstatic _Thread_local bool activate_override = false;\n\nchar *dlerror(void)\n{\n    if (!USE_DLERROR_OVERRIDE)\n       return real_dlerror();\n    \n    if (activate_override)\n    {\n        // Deactivate the override for next call to allow\n        // real_dlerror to be used\n        activate_override = false;\n        return error_override;\n    } else if (error_override) {\n        // Free resources that was allocated for error override\n        // because the override is now deactivated\n        free(error_override);\n        error_override = NULL;\n    }\n\n    return real_dlerror();\n}\n\nstatic void save_and_consume_real_dlerror()\n{\n    if (!USE_DLERROR_OVERRIDE)\n       return;\n    \n    char* recent_error = real_dlerror();\n    if (!recent_error)\n    {\n        error_override = recent_error;\n        return;\n    }\n    \n    size_t error_length = strlen(recent_error);\n    error_override = malloc(error_length + 1);\n    memcpy(error_override, recent_error, error_length + 1);\n}\n\nvoid* dlsym(void *handle, const char *name)\n{\n    save_and_consume_real_dlerror();\n    // const char* dlsym_enabled = getenv(\"MANGOHUD_DLSYM\");\n    // const char* dlsym_RTLD_NEXT_env = getenv(\"MANGOHUD_DLSYM_RTLD_NEXT\");\n    // const bool bypass_RTLD_NEXT = dlsym_RTLD_NEXT_env ? dlsym_RTLD_NEXT_env[0] == '0' : false;\n    void* is_angle = real_dlsym(handle, \"eglStreamPostD3DTextureANGLE\");\n    // Consume error message if there was an error\n    if (!is_angle)\n    {\n        (void) real_dlerror();\n    }\n\n    void* fn_ptr = real_dlsym(handle, name);\n    // Overriding dlsym makes it behave differently due to the change in search scope\n    // this results in name resolution failure when no handle or default handles are used\n    // as a mitigation we get a handle to the caller, and use it instead.\n    // This makes RTLD_DEFAULT behave better, but RTLD_NEXT is still broken.\n    // Note, RTLD_DEFAULT might still be broken for edge cases.\n\n    // this causes issues with nvidia and will crash. Needs to be reworked\n    // if (!fn_ptr && (handle == RTLD_DEFAULT || (handle == RTLD_NEXT && !bypass_RTLD_NEXT)))\n    // {\n    //     void* ret_addr = __builtin_extract_return_addr(__builtin_return_address(0));\n    //     Dl_info dl_info = {};\n\n    //     if (dladdr(ret_addr, &dl_info) && dl_info.dli_fname && dl_info.dli_fname[0])\n    //     {\n    //         void* caller_handle = dlopen(dl_info.dli_fname, RTLD_LAZY | RTLD_NOLOAD);\n    //         if (caller_handle)\n    //         {\n    //             // last real_dlsym call failed so we consume the last error\n    //             (void) real_dlerror();\n    //             fn_ptr = real_dlsym(caller_handle, name);\n    //             if (handle == RTLD_NEXT)\n    //             {\n    //                 fprintf(stderr, \"MANGOHUD: WARNING dlsym called with RTLD_NEXT, if you are facing issues try to disable mangohud.\\n\");\n    //                 fprintf(stderr, \"MANGOHUD: or you can try MANGOHUD_DLSYM_RTLD_NEXT=0\\n\");\n    //             }\n    //         }\n    //     }\n    // }\n\n    // Activate override if there wasn't any new error\n    // from real_dlsym\n    activate_override = fn_ptr != NULL;\n\n    if (!is_angle && fn_ptr)\n    {\n        for (unsigned i = 0; i < ARRAY_SIZE(hooks); i++)\n        {\n            if (!strcmp(hooks[i].name, name))\n            {\n                return hooks[i].ptr;\n            }\n        }\n    }\n\n    return fn_ptr;\n}\n"
  },
  {
    "path": "src/gpu.cpp",
    "content": "#include \"gpu.h\"\n#include \"file_utils.h\"\n#include \"hud_elements.h\"\n\nnamespace fs = ghc::filesystem;\n\nGPUS::GPUS(const overlay_params* early_params) {\n    std::set<std::string> gpu_entries;\n    auto params = early_params ? early_params : get_params().get();\n\n    for (const auto& entry : fs::directory_iterator(\"/sys/class/drm\")) {\n        if (!entry.is_directory())\n            continue;\n\n        std::string node_name = entry.path().filename().string();\n\n        // Check if the directory is a render node (e.g., renderD128, renderD129, etc.)\n        if (node_name.find(\"renderD\") == 0 && node_name.length() > 7) {\n            // Ensure the rest of the string after \"renderD\" is numeric\n            std::string render_number = node_name.substr(7);\n            if (std::all_of(render_number.begin(), render_number.end(), ::isdigit)) {\n                gpu_entries.insert(node_name);  // Store the render entry\n            }\n        }\n    }\n\n    // Now process the sorted GPU entries\n    uint8_t idx = 0, total_active = 0;\n\n    for (const auto& node_name : gpu_entries) {\n        const std::string driver = get_driver(node_name);\n\n        if (driver.empty()) {\n            SPDLOG_DEBUG(\"Failed to query driver name of node \\\"{}\\\"\", node_name);\n            continue;\n        }\n\n        {\n            const std::string* d =\n                std::find(std::begin(supported_drivers), std::end(supported_drivers), driver);\n\n            if (d == std::end(supported_drivers)) {\n                SPDLOG_WARN(\n                    \"node \\\"{}\\\" is using driver \\\"{}\\\" which is unsupported by MangoHud. Skipping...\",\n                    node_name, driver\n                );\n                continue;\n            }\n        }\n\n        std::string path = \"/sys/class/drm/\" + node_name;\n        std::string device_address = get_pci_device_address(path);  // Store the result\n        const char* pci_dev = device_address.c_str();\n\n        uint32_t vendor_id = 0;\n        uint32_t device_id = 0;\n\n        if (!device_address.empty())\n        {\n            try {\n                vendor_id = std::stoul(read_line(\"/sys/bus/pci/devices/\" + device_address + \"/vendor\"), nullptr, 16);\n            } catch(...) {\n                SPDLOG_ERROR(\"stoul failed on: {}\", \"/sys/bus/pci/devices/\" + device_address + \"/vendor\");\n            }\n\n            try {\n                device_id = std::stoul(read_line(\"/sys/bus/pci/devices/\" + device_address + \"/device\"), nullptr, 16);\n            } catch (...) {\n                SPDLOG_ERROR(\"stoul failed on: {}\", \"/sys/bus/pci/devices/\" + device_address + \"/device\");\n            }\n        }\n\n        std::shared_ptr<GPU> ptr =\n            std::make_shared<GPU>(node_name, vendor_id, device_id, pci_dev, driver);\n\n        if (params->gpu_list.size() == 1 && params->gpu_list[0] == idx++)\n            ptr->is_active = true;\n\n        if (!params->pci_dev.empty() && pci_dev == params->pci_dev)\n            ptr->is_active = true;\n\n        available_gpus.emplace_back(ptr);\n\n        SPDLOG_DEBUG(\n            \"GPU Found: node_name: {}, driver: {}, vendor_id: {:x} device_id: {:x} pci_dev: {}\",\n            node_name, driver, vendor_id, device_id, pci_dev\n        );\n\n        if (ptr->is_active) {\n            SPDLOG_INFO(\n                \"Set {} as active GPU (driver={} id={:x}:{:x} pci_dev={})\",\n                node_name, driver, vendor_id, device_id, pci_dev\n            );\n            total_active++;\n        }\n    }\n\n    if (total_active < 2)\n        return;\n\n    for (auto& gpu : available_gpus) {\n        if (!gpu->is_active)\n            continue;\n\n        SPDLOG_WARN(\n            \"You have more than 1 active GPU, check if you use both pci_dev \"\n            \"and gpu_list. If you use fps logging, MangoHud will log only \"\n            \"this GPU: name = {}, driver = {}, vendor = {:x}, pci_dev = {}\",\n            gpu->drm_node, gpu->driver, gpu->vendor_id, gpu->pci_dev\n        );\n\n        break;\n    }\n\n}\n\nstd::string GPUS::get_driver(const std::string& node) {\n    std::string path = \"/sys/class/drm/\" + node + \"/device/driver\";\n\n    if (!fs::exists(path)) {\n        SPDLOG_ERROR(\"{} doesn't exist\", path);\n        return \"\";\n    }\n\n    if (!fs::is_symlink(path)) {\n        SPDLOG_ERROR(\"{} is not a symlink (it should be)\", path);\n        return \"\";\n    }\n\n    std::string driver = fs::read_symlink(path).string();\n    driver = driver.substr(driver.rfind(\"/\") + 1);\n\n    return driver;\n}\n\nstd::string GPUS::get_pci_device_address(const std::string& drm_card_path) {\n    // /sys/class/drm/renderD128/device/subsystem -> /sys/bus/pci\n    auto subsystem = fs::canonical(drm_card_path + \"/device/subsystem\").string();\n    auto idx = subsystem.rfind(\"/\") + 1; // /sys/bus/pci\n                                         //         ^\n                                         //         |- find this guy\n    if (subsystem.substr(idx) != \"pci\")\n        return \"\";\n\n    // /sys/class/drm/renderD128/device -> /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0\n    auto pci_addr = fs::read_symlink(drm_card_path + \"/device\").string();\n    idx = pci_addr.rfind(\"/\") + 1; // /sys/.../0000:03:00.0\n                                   //         ^\n                                   //         |- find this guy\n\n    return pci_addr.substr(idx); // 0000:03:00.0\n}\n\nint GPU::index_in_selected_gpus() {\n    auto selected_gpus = gpus->selected_gpus();\n    auto it = std::find_if(selected_gpus.begin(), selected_gpus.end(),\n                        [this](const std::shared_ptr<GPU>& gpu) {\n                            return gpu.get() == this;\n                        });\n    if (it != selected_gpus.end()) {\n        return std::distance(selected_gpus.begin(), it);\n    }\n    return -1;\n}\n\nstd::string GPU::gpu_text() {\n    std::string gpu_text;\n    size_t index = this->index_in_selected_gpus();\n\n    if (gpus->selected_gpus().size() == 1) {\n        // When there's exactly one selected GPU, return \"GPU\" without index\n        gpu_text = \"GPU\";\n        if (gpus->params()->gpu_text.size() > 0) {\n            gpu_text = gpus->params()->gpu_text[0];\n        }\n    } else if (gpus->selected_gpus().size() > 1) {\n        // When there are multiple selected GPUs, use GPU+index or matching gpu_text\n        gpu_text = \"GPU\" + std::to_string(index);\n        if (gpus->params()->gpu_text.size() > index) {\n            gpu_text = gpus->params()->gpu_text[index];\n        }\n    } else {\n        // Default case for no selected GPUs\n        gpu_text = \"GPU\";\n    }\n\n    return gpu_text;\n}\n\nstd::string GPU::vram_text() {\n    std::string vram_text;\n    size_t index = this->index_in_selected_gpus();\n    if (gpus->selected_gpus().size() > 1)\n        vram_text = \"VRAM\" + std::to_string(index);\n    else\n        vram_text = \"VRAM\";\n    return vram_text;\n}\n\nstd::shared_ptr<const overlay_params> GPUS::params() {\n    return get_params();\n}\n\nstd::unique_ptr<GPUS> gpus = nullptr;\n"
  },
  {
    "path": "src/gpu.h",
    "content": "#pragma once\n#ifndef MANGOHUD_GPU_H\n#define MANGOHUD_GPU_H\n\n#include <cstdio>\n#include <cstdint>\n#include \"overlay_params.h\"\n#include <thread>\n#include <mutex>\n#include <atomic>\n#include <chrono>\n#include <regex>\n#include <iostream>\n#include <array>\n#include \"amdgpu.h\"\n#include \"nvidia.h\"\n#include \"gpu_metrics_util.h\"\n#include \"gpu_fdinfo.h\"\n\nclass GPU {\n    public:\n        gpu_metrics metrics;\n        std::string drm_node;\n        std::unique_ptr<NVIDIA> nvidia = nullptr;\n        std::unique_ptr<AMDGPU> amdgpu = nullptr;\n        std::unique_ptr<GPU_fdinfo> fdinfo = nullptr;\n        bool is_active = false;\n        std::string pci_dev;\n        uint32_t vendor_id = 0;\n        uint32_t device_id = 0;\n        const std::string driver;\n\n        GPU(\n            std::string drm_node, uint32_t vendor_id, uint32_t device_id, const char* pci_dev,\n            std::string driver\n        )\n            : drm_node(drm_node), pci_dev(pci_dev), vendor_id(vendor_id), device_id(device_id),\n            driver(driver) {\n                if (vendor_id == 0x10de)\n                    nvidia = std::make_unique<NVIDIA>(pci_dev);\n\n                if (vendor_id == 0x1002)\n                    amdgpu = std::make_unique<AMDGPU>(pci_dev, device_id, vendor_id);\n\n                if (\n                    driver == \"i915\" || driver == \"xe\" ||\n                    driver == \"panfrost\" || driver == \"panthor\" ||\n                    driver == \"msm_dpu\" || driver == \"msm_drm\"\n                )\n                    fdinfo = std::make_unique<GPU_fdinfo>(driver, pci_dev, drm_node);\n        }\n\n        gpu_metrics get_metrics() {\n            if (nvidia)\n                this->metrics = nvidia->copy_metrics();\n\n            if (amdgpu)\n                this->metrics = amdgpu->copy_metrics();\n\n            if (fdinfo)\n                this->metrics = fdinfo->copy_metrics();\n\n            return metrics;\n        };\n\n        std::vector<int> nvidia_pids() {\n#ifdef HAVE_NVML\n            if (nvidia)\n                return nvidia->pids();\n#endif\n            return std::vector<int>();\n        }\n\n        void pause() {\n            if (nvidia)\n                nvidia->pause();\n\n            if (amdgpu)\n                amdgpu->pause();\n\n            if (fdinfo)\n                fdinfo->pause();\n        }\n\n        void resume() {\n            if (nvidia)\n                nvidia->resume();\n\n            if (amdgpu)\n                amdgpu->resume();\n\n            if (fdinfo)\n                fdinfo->resume();\n        }\n\n        bool is_apu() {\n            if (amdgpu)\n                return amdgpu->is_apu;\n            else\n                return false;\n        }\n\n        std::shared_ptr<Throttling> throttling() {\n            if (nvidia)\n                return nvidia->throttling;\n\n            if (amdgpu)\n                return amdgpu->throttling;\n\n            return nullptr;\n        }\n\n        std::string gpu_text();\n        std::string vram_text();\n\n    private:\n        std::thread thread;\n\n        int index_in_selected_gpus();\n};\n\nclass GPUS {\n    public:\n        std::vector<std::shared_ptr<GPU>> available_gpus;\n        std::mutex mutex;\n\n        explicit GPUS(const overlay_params* early_params = nullptr);\n\n        std::shared_ptr<const overlay_params> params();\n\n        void pause() {\n            for (auto& gpu : available_gpus)\n                gpu->pause();\n        }\n\n        void resume() {\n            for (auto& gpu : available_gpus)\n                gpu->resume();\n        }\n\n        std::shared_ptr<GPU> active_gpu() {\n            if (available_gpus.empty())\n                return nullptr;\n\n            for (auto gpu : available_gpus) {\n                if (gpu->is_active)\n                    return gpu;\n            }\n\n            // if no GPU is marked as active, just set it to the last one\n            // because integrated gpus are usually first\n            return available_gpus.back();\n        }\n\n        void update_throttling() {\n            for (auto gpu : available_gpus)\n                if (gpu->throttling())\n                    gpu->throttling()->update();\n        }\n\n        void get_metrics() {\n            std::lock_guard<std::mutex> lock(mutex);\n            for (auto gpu : available_gpus)\n                gpu->get_metrics();\n        }\n\n        std::vector<std::shared_ptr<GPU>> selected_gpus() {\n            std::lock_guard<std::mutex> lock(mutex);\n            std::vector<std::shared_ptr<GPU>> vec;\n\n            if (params()->gpu_list.empty() && params()->pci_dev.empty())\n                return available_gpus;\n\n            if (!params()->gpu_list.empty()) {\n                for (unsigned index : params()->gpu_list) {\n                    if (index < available_gpus.size()) {\n                        if (available_gpus[index])\n                            vec.push_back(available_gpus[index]);\n                    }\n                }\n\n                return vec;\n            }\n\n            if (!params()->pci_dev.empty()) {\n                for (auto &gpu : available_gpus) {\n                    if (gpu->pci_dev == params()->pci_dev) {\n                        vec.push_back(gpu);\n                        return vec;\n                    }\n                }\n\n                return vec;\n            }\n\n            return vec;\n        }\n\n    private:\n        std::string get_pci_device_address(const std::string& drm_card_path);\n        std::string get_driver(const std::string& node);\n\n        const std::array<std::string, 8> supported_drivers = {\n            \"amdgpu\", \"nvidia\", \"i915\", \"xe\", \"panfrost\", \"panthor\", \"msm_dpu\", \"msm_drm\"\n        };\n};\n\nextern std::unique_ptr<GPUS> gpus;\n\nvoid getNvidiaGpuInfo(const struct overlay_params& params);\nvoid getAmdGpuInfo(void);\nvoid getIntelGpuInfo();\nbool checkNvidia(const char *pci_dev);\nextern void nvapi_util();\nextern bool checkNVAPI();\n#endif //MANGOHUD_GPU_H\n"
  },
  {
    "path": "src/gpu_fdinfo.cpp",
    "content": "#include \"gpu_fdinfo.h\"\n\n#ifndef TEST_ONLY\n#include \"hud_elements.h\"\n#endif\n\nnamespace fs = ghc::filesystem;\n\nvoid GPU_fdinfo::find_fd()\n{\n    fdinfo.clear();\n    fdinfo_data.clear();\n\n    auto dir = std::string(\"/proc/\") + std::to_string(pid) + \"/fdinfo\";\n    auto path = fs::path(dir);\n\n    SPDLOG_TRACE(\"fdinfo_dir = {}\", dir);\n\n    if (!fs::exists(path)) {\n        SPDLOG_DEBUG(\"{} does not exist\", path.string());\n        return;\n    }\n\n    // Here we store client-ids, if ids match, we dont open this file,\n    // because it will have same readings and it becomes a duplicate\n    std::set<std::string> client_ids;\n    int total = 0;\n\n    for (const auto& entry : fs::directory_iterator(path)) {\n        auto fd_path = entry.path().string();\n        auto file = std::ifstream(fd_path);\n\n        if (!file.is_open())\n            continue;\n\n        std::string driver, pdev, client_id;\n\n        for (std::string line; std::getline(file, line);) {\n            size_t colon = line.find(\":\");\n\n            if (line[0] == ' ' || line[0] == '\\t')\n                continue;\n\n            if (colon == std::string::npos || colon + 2 >= line.length())\n                continue;\n\n            auto key = line.substr(0, colon);\n            auto val = line.substr(key.length() + 2);\n\n            if (key == \"drm-driver\")\n                driver = val;\n            else if (key == \"drm-pdev\")\n                pdev = val;\n            else if (key == \"drm-client-id\")\n                client_id = val;\n        }\n\n        if (!driver.empty() && driver == module) {\n            total++;\n            SPDLOG_TRACE(\n                \"driver = \\\"{}\\\", pdev = \\\"{}\\\", \"\n                \"client_id = \\\"{}\\\", client_id_exists = \\\"{}\\\"\",\n                driver, pdev,\n                client_id, client_ids.find(client_id) != client_ids.end()\n            );\n        }\n\n        if (\n            driver.empty() || client_id.empty() ||\n            driver != module || pdev != pci_dev ||\n            client_ids.find(client_id) != client_ids.end()\n        )\n            continue;\n\n        client_ids.insert(client_id);\n        open_fdinfo_fd(fd_path);\n    }\n\n    SPDLOG_TRACE(\n        \"Found {} total fds. Opened {} unique fds.\",\n        total,\n        fdinfo.size()\n    );\n}\n\nvoid GPU_fdinfo::open_fdinfo_fd(std::string path) {\n    fdinfo.push_back(std::ifstream(path));\n    fdinfo_data.push_back({});\n}\n\nvoid GPU_fdinfo::gather_fdinfo_data() {\n    for (size_t i = 0; i < fdinfo.size(); i++) {\n        fdinfo[i].clear();\n        fdinfo[i].seekg(0);\n\n        for (std::string line; std::getline(fdinfo[i], line);) {\n            size_t colon = line.find(\":\");\n\n            if (line[0] == ' ' || line[0] == '\\t')\n                continue;\n\n            if (colon == std::string::npos || colon + 2 >= line.length())\n                continue;\n\n            auto key = line.substr(0, line.find(\":\"));\n            auto val = line.substr(key.length() + 2);\n            fdinfo_data[i][key] = val;\n        }\n    }\n}\n\nuint64_t GPU_fdinfo::get_gpu_time()\n{\n    uint64_t total = 0;\n\n    if (module == \"panfrost\")\n        return get_gpu_time_panfrost();\n\n    for (auto& fd : fdinfo_data) {\n        auto time = fd[drm_engine_type];\n\n        if (time.empty())\n            continue;\n\n        total += std::stoull(time);\n    }\n\n    return total;\n}\n\nuint64_t GPU_fdinfo::get_gpu_time_panfrost() {\n    uint64_t total = 0;\n\n    for (auto& fd : fdinfo_data) {\n        auto frag = fd[\"drm-engine-fragment\"];\n        auto vert = fd[\"drm-engine-vertex-tiler\"];\n\n        if (!frag.empty())\n            total += std::stoull(frag);\n\n        if (!vert.empty())\n            total += std::stoull(vert);\n    }\n\n    return total;\n}\n\nfloat GPU_fdinfo::get_memory_used()\n{\n    uint64_t total = 0;\n\n    for (auto& fd : fdinfo_data) {\n        auto mem = fd[drm_memory_type];\n\n        if (mem.empty())\n            continue;\n\n        std::string unit = mem.substr(mem.rfind(\" \") + 1);\n        uint64_t val = std::stoull(mem);\n\n        if (unit == \"KiB\")\n            val *= 1024;\n        else if (unit == \"MiB\")\n            val *= 1024 * 1024;\n        else if (unit == \"GiB\")\n            val *= 1024 * 1024 * 1024;\n\n        total += val;\n    }\n\n    return static_cast<float>(total) / 1024 / 1024 / 1024;\n}\n\nvoid GPU_fdinfo::find_hwmon_sensors()\n{\n    std::string hwmon;\n\n    if (module == \"msm\")\n        hwmon = find_hwmon_sensor_dir(\"gpu\");\n    else if (module == \"panfrost\" || module == \"panthor\")\n        hwmon = find_hwmon_sensor_dir(\"gpu_thermal\");\n    else\n        hwmon = find_hwmon_dir();\n\n    if (hwmon.empty()) {\n        SPDLOG_DEBUG(\"hwmon: failed to find hwmon directory\");\n        return;\n    }\n\n    SPDLOG_DEBUG(\"hwmon: checking \\\"{}\\\" directory\", hwmon);\n\n    for (const auto &entry : fs::directory_iterator(hwmon)) {\n        auto filename = entry.path().filename().string();\n\n        for (auto& hs : hwmon_sensors) {\n            auto key = hs.first;\n            auto sensor = &hs.second;\n            std::smatch matches;\n\n            if (\n                !std::regex_match(filename, matches, sensor->rx) ||\n                matches.size() != 2\n            )\n                continue;\n\n            auto cur_id = std::stoull(matches[1].str());\n\n            if (sensor->filename.empty() || cur_id < sensor->id) {\n                sensor->filename = entry.path().string();\n                sensor->id = cur_id;\n            }\n        }\n    }\n\n    for (auto& hs : hwmon_sensors) {\n        auto key = hs.first;\n        auto sensor = &hs.second;\n\n        if (sensor->filename.empty()) {\n            SPDLOG_DEBUG(\"hwmon: {} reading not found at {}\", key, hwmon);\n            continue;\n        }\n\n        SPDLOG_DEBUG(\"hwmon: {} reading found at {}\", key, sensor->filename);\n\n        sensor->stream.open(sensor->filename);\n\n        if (!sensor->stream.good()) {\n            SPDLOG_DEBUG(\n                \"hwmon: failed to open {} reading {}\",\n                key, sensor->filename\n            );\n            continue;\n        }\n    }\n}\n\nstd::string GPU_fdinfo::find_hwmon_dir() {\n    std::string d = \"/sys/class/drm/\" + drm_node + \"/device/hwmon\";\n\n    if (!fs::exists(d)) {\n        SPDLOG_DEBUG(\"hwmon: hwmon directory \\\"{}\\\" doesn't exist\", d);\n        return \"\";\n    }\n\n    auto dir_iterator = fs::directory_iterator(d);\n    auto hwmon = dir_iterator->path().string();\n\n    if (hwmon.empty()) {\n        SPDLOG_DEBUG(\"hwmon: hwmon directory \\\"{}\\\" is empty.\", d);\n        return \"\";\n    }\n\n    return hwmon;\n}\n\nstd::string GPU_fdinfo::find_hwmon_sensor_dir(std::string name) {\n    std::string d = \"/sys/class/hwmon/\";\n\n    if (!fs::exists(d))\n        return \"\";\n\n    for (const auto &entry : fs::directory_iterator(d)) {\n        auto hwmon_dir = entry.path().string();\n        auto hwmon_name = hwmon_dir + \"/name\";\n\n        std::ifstream name_stream(hwmon_name);\n        std::string name_content;\n\n        if (!name_stream.is_open())\n            continue;\n\n        std::getline(name_stream, name_content);\n\n        if (name_content.find(name) == std::string::npos)\n            continue;\n\n        // return the first gpu sensor\n        return hwmon_dir;\n    }\n\n    return \"\";\n}\n\nvoid GPU_fdinfo::get_current_hwmon_readings()\n{\n    for (auto& hs : hwmon_sensors) {\n        auto key = hs.first;\n        auto sensor = &hs.second;\n\n        if (!sensor->stream.is_open())\n            continue;\n\n        sensor->stream.seekg(0);\n\n        std::stringstream ss;\n        ss << sensor->stream.rdbuf();\n\n        if (ss.str().empty())\n            continue;\n\n        sensor->val = std::stoull(ss.str());\n    }\n}\n\nfloat GPU_fdinfo::get_power_usage()\n{\n    if (!hwmon_sensors[\"power\"].filename.empty())\n        return static_cast<float>(hwmon_sensors[\"power\"].val) / 1'000'000;\n\n    float now = hwmon_sensors[\"energy\"].val;\n\n    // Initialize value for the first time, otherwise delta will be very large\n    // and your gpu power usage will be like 1 million watts for a second.\n    if (this->last_power == 0.f)\n        this->last_power = now;\n\n    float delta = now - this->last_power;\n    delta /= METRICS_UPDATE_PERIOD_MS / 1000.f;\n\n    this->last_power = now;\n\n    return delta / 1'000'000;\n}\n\nint GPU_fdinfo::get_xe_load()\n{\n    double load = 0;\n\n    for (auto& fd : fdinfo_data) {\n        std::string client_id = fd[\"drm-client-id\"];\n        std::string cur_cycles_str = fd[\"drm-cycles-rcs\"];\n        std::string cur_total_cycles_str = fd[\"drm-total-cycles-rcs\"];\n\n        if (\n            client_id.empty() || cur_cycles_str.empty() ||\n            cur_total_cycles_str.empty()\n        )\n            continue;\n\n        auto cur_cycles = std::stoull(cur_cycles_str);\n        auto cur_total_cycles = std::stoull(cur_total_cycles_str);\n\n        if (prev_xe_cycles.find(client_id) == prev_xe_cycles.end()) {\n            prev_xe_cycles[client_id] = { cur_cycles, cur_total_cycles };\n            continue;\n        }\n\n        auto prev_cycles = prev_xe_cycles[client_id].first;\n        auto prev_total_cycles = prev_xe_cycles[client_id].second;\n\n        auto delta_cycles = cur_cycles - prev_cycles;\n        auto delta_total_cycles = cur_total_cycles - prev_total_cycles;\n\n        prev_xe_cycles[client_id] = { cur_cycles, cur_total_cycles };\n\n        if (delta_cycles <= 0 || delta_total_cycles <= 0)\n            continue;\n\n        auto fd_load = static_cast<double>(delta_cycles) / delta_total_cycles * 100;\n        load += fd_load;\n    }\n\n    if (load > 100.f)\n        load = 100.f;\n\n    return std::lround(load);\n}\n\nint GPU_fdinfo::get_gpu_load()\n{\n    if (module == \"xe\")\n        return get_xe_load();\n    else if (module == \"msm_drm\")\n        return get_kgsl_load();\n\n    uint64_t now = os_time_get_nano();\n    uint64_t gpu_time_now = get_gpu_time();\n\n    if (previous_time == 0) {\n        previous_gpu_time = gpu_time_now;\n        previous_time = now;\n\n        return 0;\n    }\n\n    float delta_time = now - previous_time;\n    float delta_gpu_time = gpu_time_now - previous_gpu_time;\n\n    int result = delta_gpu_time / delta_time * 100;\n\n    if (result > 100)\n        result = 100;\n\n    previous_gpu_time = gpu_time_now;\n    previous_time = now;\n\n    return std::round(result);\n}\n\nvoid GPU_fdinfo::find_i915_gt_dir()\n{\n    std::string device = \"/sys/bus/pci/devices/\" + pci_dev + \"/drm\";\n\n    // Find first dir which starts with name \"card\"\n    for (const auto& entry : fs::directory_iterator(device)) {\n        auto path = entry.path().string();\n\n        if (path.substr(device.size() + 1, 4) == \"card\") {\n            device = path;\n            break;\n        }\n    }\n\n    auto gpu_clock_path = device + \"/gt_act_freq_mhz\";\n    gpu_clock_stream.open(gpu_clock_path);\n\n    if (!gpu_clock_stream.good())\n        SPDLOG_WARN(\"Intel i915 gt dir: failed to open {}\", device);\n\n    // Assuming gt0 since all recent GPUs have the RCS engine on gt0,\n    // and latest GPUs need Xe anyway\n    auto throttle_folder = device + \"/gt/gt0/throttle_\";\n    auto throttle_status_path = throttle_folder + \"reason_status\";\n\n    throttle_status_stream.open(throttle_status_path);\n    if (!throttle_status_stream.good()) {\n       SPDLOG_WARN(\"Intel i915 gt dir: failed to open {}\", throttle_status_path);\n    } else {\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_power,\n                                      throttle_power_streams);\n\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_current,\n                                      throttle_current_streams);\n\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_temp,\n                                      throttle_temp_streams);\n    }\n}\n\nvoid GPU_fdinfo::find_xe_gt_dir()\n{\n    std::string device = \"/sys/bus/pci/devices/\" + pci_dev + \"/tile0\";\n\n    if (!fs::exists(device)) {\n        SPDLOG_WARN(\n            \"\\\"{}\\\" doesn't exist. GPU clock will be unavailable.\",\n            device\n        );\n        return;\n    }\n\n    bool has_rcs = true;\n\n    // Check every \"gt\" dir if it has \"engines/rcs\" inside\n    for (const auto& entry : fs::directory_iterator(device)) {\n        auto path = entry.path().string();\n\n        if (path.substr(device.size() + 1, 2) != \"gt\")\n            continue;\n\n        SPDLOG_DEBUG(\"Checking \\\"{}\\\" for rcs.\", path);\n\n        if (!fs::exists(path + \"/engines/rcs\")) {\n            SPDLOG_DEBUG(\"Skipping \\\"{}\\\" because rcs doesn't exist.\", path);\n            continue;\n        }\n\n        SPDLOG_DEBUG(\"Found rcs in \\\"{}\\\"\", path);\n        has_rcs = true;\n        device = path;\n        break;\n\n    }\n\n    if (!has_rcs) {\n        SPDLOG_WARN(\n            \"rcs not found inside \\\"{}\\\". GPU clock will not be available.\",\n            device\n        );\n        return;\n    }\n\n    auto gpu_clock_path = device + \"/freq0/act_freq\";\n    gpu_clock_stream.open(gpu_clock_path);\n\n    if (!gpu_clock_stream.good())\n        SPDLOG_WARN(\"Intel xe gt dir: failed to open {}\", gpu_clock_path);\n\n    auto throttle_folder = device + \"/freq0/throttle/\";\n    auto throttle_status_path = throttle_folder + \"status\";\n\n    throttle_status_stream.open(throttle_status_path);\n    if (!throttle_status_stream.good()) {\n       SPDLOG_WARN(\"Intel xe gt dir: failed to open {}\", throttle_status_path);\n    } else {\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_power,\n                                      throttle_power_streams);\n\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_current,\n                                      throttle_current_streams);\n\n        load_xe_i915_throttle_reasons(throttle_folder,\n                                      intel_throttle_temp,\n                                      throttle_temp_streams);\n    }\n}\n\nvoid GPU_fdinfo::load_xe_i915_throttle_reasons(\n    std::string throttle_folder,\n    std::vector<std::string> throttle_reasons,\n    std::vector<std::ifstream>& throttle_reason_streams\n) {\n    for (const auto& throttle_reason : throttle_reasons) {\n        std::string throttle_path = throttle_folder + throttle_reason;\n        if (!fs::exists(throttle_path)) {\n            SPDLOG_WARN(\n                \"Intel xe/i915 gt dir: Throttle file {} not found\",\n                throttle_path\n            );\n            continue;\n        }\n        auto throttle_stream = std::ifstream(throttle_path);\n        if (!throttle_stream.good()) {\n            SPDLOG_WARN(\"Intel xe/i915 gt dir: failed to open {}\", throttle_path);\n            continue;\n        }\n        throttle_reason_streams.push_back(std::move(throttle_stream));\n    }\n}\n\nint GPU_fdinfo::get_gpu_clock()\n{\n    if (module == \"panfrost\" || module == \"panthor\")\n        return get_gpu_clock_mali();\n\n    if (!gpu_clock_stream.is_open())\n        return 0;\n\n    std::string clock_str;\n\n    gpu_clock_stream.seekg(0);\n\n    std::getline(gpu_clock_stream, clock_str);\n\n    if (clock_str.empty())\n        return 0;\n\n    return std::stoi(clock_str);\n}\n\nint GPU_fdinfo::get_gpu_clock_mali() {\n    if (fdinfo_data.empty())\n        return 0;\n\n    std::string key;\n\n    if (module == \"panfrost\")\n        key = \"drm-curfreq-fragment\";\n    else if (module == \"panthor\")\n        key = \"drm-curfreq-panthor\";\n\n    std::string freq_str = fdinfo_data[0][key];\n\n    if (freq_str.empty())\n        return 0;\n\n    float freq = std::stoull(freq_str) / 1'000'000;\n\n    return std::round(freq);\n}\n\nbool GPU_fdinfo::check_throttle_reasons(\n    std::vector<std::ifstream>& throttle_reason_streams)\n{\n    for (auto& throttle_reason_stream : throttle_reason_streams) {\n        std::string throttle_reason_str;\n        throttle_reason_stream.seekg(0);\n        std::getline(throttle_reason_stream, throttle_reason_str);\n\n        if (throttle_reason_str == \"1\")\n            return true;\n    }\n\n    return false;\n}\n\nint GPU_fdinfo::get_throttling_status()\n{\n    if (!throttle_status_stream.is_open())\n        return 0;\n\n    std::string throttle_status_str;\n    throttle_status_stream.seekg(0);\n    std::getline(throttle_status_stream, throttle_status_str);\n\n    if (throttle_status_str != \"1\")\n        return 0;\n\n    int reasons =\n        check_throttle_reasons(throttle_power_streams) * GPU_throttle_status::POWER +\n        check_throttle_reasons(throttle_current_streams) * GPU_throttle_status::CURRENT +\n        check_throttle_reasons(throttle_temp_streams) * GPU_throttle_status::TEMP;\n    // No throttle reasons for OTHER currently\n    if (reasons == 0)\n        reasons |= GPU_throttle_status::OTHER;\n\n    return reasons;\n}\n\nfloat GPU_fdinfo::amdgpu_helper_get_proc_vram() {\n#ifndef TEST_ONLY\n    if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid)\n    {\n        pid = HUDElements.g_gamescopePid;\n        find_fd();\n    }\n#endif\n\n    // Recheck fds every 10secs, fixes Mass Effect 1, maybe some others too\n    {\n        auto t = os_time_get_nano() / 1'000'000;\n        if (t - fdinfo_last_update_ms >= 10'000) {\n            find_fd();\n            fdinfo_last_update_ms = t;\n        }\n    }\n\n    gather_fdinfo_data();\n\n    return get_memory_used();\n}\n\nvoid GPU_fdinfo::init_kgsl() {\n    const std::string sys_path = \"/sys/class/kgsl/kgsl-3d0\";\n\n    try {\n        if (!fs::exists(sys_path)) {\n            SPDLOG_WARN(\"kgsl: {} is not found. kgsl stats will not work!\", sys_path);\n            return;\n        }\n    } catch (fs::filesystem_error& ex) {\n        SPDLOG_WARN(\"kgsl: {}\", ex.what());\n        return;\n    }\n\n    for (std::string metric : {\"gpu_busy_percentage\", \"temp\", \"clock_mhz\" }) {\n        std::string p = sys_path + \"/\" + metric;\n\n        if (!fs::exists(p)) {\n            SPDLOG_WARN(\"kgsl: {} is not found\", p);\n            continue;\n        }\n\n        SPDLOG_DEBUG(\"kgsl: {} found\", p);\n\n        if (metric == \"clock_mhz\")\n            gpu_clock_stream.open(p);\n        else\n            kgsl_streams[metric].open(p);\n    }\n}\n\nint GPU_fdinfo::get_kgsl_load() {\n    std::ifstream* s = &kgsl_streams[\"gpu_busy_percentage\"];\n\n    if (!s->is_open())\n        return 0;\n\n    std::string usage_str;\n\n    s->seekg(0);\n\n    std::getline(*s, usage_str);\n\n    if (usage_str.empty())\n        return 0;\n\n    return std::stoi(usage_str);\n}\n\nint GPU_fdinfo::get_kgsl_temp() {\n    std::ifstream* s = &kgsl_streams[\"temp\"];\n\n    if (!s->is_open())\n        return 0;\n\n    std::string temp_str;\n\n    s->seekg(0);\n\n    std::getline(*s, temp_str);\n\n    if (temp_str.empty())\n        return 0;\n\n    return std::round(std::stoi(temp_str) / 1'000.f);\n}\n\nvoid GPU_fdinfo::main_thread()\n{\n    while (!stop_thread) {\n        std::unique_lock<std::mutex> lock(metrics_mutex);\n        cond_var.wait(lock, [this]() { return !paused || stop_thread; });\n\n#ifndef TEST_ONLY\n        if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid)\n        {\n            pid = HUDElements.g_gamescopePid;\n            find_fd();\n        }\n#endif\n\n        // Recheck fds every 10secs, fixes Mass Effect 1, maybe some others too\n        {\n            auto t = os_time_get_nano() / 1'000'000;\n            if (t - fdinfo_last_update_ms >= 10'000) {\n                find_fd();\n                fdinfo_last_update_ms = t;\n            }\n        }\n\n        gather_fdinfo_data();\n        get_current_hwmon_readings();\n\n        metrics.load = get_gpu_load();\n        metrics.proc_vram_used = get_memory_used();\n\n        metrics.powerUsage = get_power_usage();\n        metrics.powerLimit = static_cast<float>(hwmon_sensors[\"power_limit\"].val) / 1'000'000;\n\n        metrics.CoreClock = get_gpu_clock();\n        metrics.voltage = hwmon_sensors[\"voltage\"].val;\n\n        if (module == \"msm_drm\")\n            metrics.temp = get_kgsl_temp();\n        else\n            metrics.temp = hwmon_sensors[\"temp\"].val / 1000.f;\n\n        metrics.memory_temp = hwmon_sensors[\"vram_temp\"].val / 1000.f;\n\n        metrics.fan_speed = hwmon_sensors[\"fan_speed\"].val;\n        metrics.fan_rpm = true; // Fan data is pulled from hwmon\n\n        int throttling = get_throttling_status();\n        metrics.is_power_throttled = throttling & GPU_throttle_status::POWER;\n        metrics.is_current_throttled = throttling & GPU_throttle_status::CURRENT;\n        metrics.is_temp_throttled = throttling & GPU_throttle_status::TEMP;\n        metrics.is_other_throttled = throttling & GPU_throttle_status::OTHER;\n\n        SPDLOG_DEBUG(\n            \"pci_dev = {}, pid = {}, module = {}, \"\n            \"load = {}, proc_vram = {}, power = {}, \"\n            \"core = {}, temp = {}, fan = {}, \"\n            \"voltage = {}\",\n            pci_dev, pid, module,\n            metrics.load, metrics.proc_vram_used, metrics.powerUsage,\n            metrics.CoreClock, metrics.temp, metrics.fan_speed,\n            metrics.voltage\n        );\n\n        std::this_thread::sleep_for(\n            std::chrono::milliseconds(METRICS_UPDATE_PERIOD_MS)\n        );\n    }\n}\n"
  },
  {
    "path": "src/gpu_fdinfo.h",
    "content": "#pragma once\n\n#include <inttypes.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <cstdint>\n#include <thread>\n#include <atomic>\n#include <map>\n#include <set>\n#include <regex>\n#include <sstream>\n\n#ifdef TEST_ONLY\n#include <../src/mesa/util/os_time.h>\n#else\n#include \"mesa/util/os_time.h\"\n#endif\n\n#include <spdlog/spdlog.h>\n#include <filesystem.h>\n\n#include \"gpu_metrics_util.h\"\n\nstruct hwmon_sensor {\n    std::regex rx;\n    std::ifstream stream;\n    std::string filename;\n    unsigned char id = 0;\n    uint64_t val = 0;\n};\n\nenum GPU_throttle_status : int {\n    POWER = 0b0001,\n    CURRENT = 0b0010,\n    TEMP = 0b0100,\n    OTHER = 0b1000,\n};\n\nclass GPU_fdinfo {\nprivate:\n    pid_t pid = getpid();\n\n    const std::string module;\n    const std::string pci_dev;\n    const std::string drm_node;\n\n    std::thread thread;\n    std::condition_variable cond_var;\n\n    std::atomic<bool> stop_thread { false };\n    std::atomic<bool> paused { false };\n\n    struct gpu_metrics metrics;\n    mutable std::mutex metrics_mutex;\n\n    std::vector<std::ifstream> fdinfo;\n    uint64_t fdinfo_last_update_ms = 0;\n\n    std::map<std::string, hwmon_sensor> hwmon_sensors;\n\n    std::string drm_engine_type = \"EMPTY\";\n    std::string drm_memory_type = \"EMPTY\";\n\n    std::vector<std::map<std::string, std::string>> fdinfo_data;\n    void gather_fdinfo_data();\n\n    void main_thread();\n\n    void find_fd();\n    void open_fdinfo_fd(std::string path);\n\n    int get_gpu_load();\n    uint64_t get_gpu_time();\n\n    uint64_t previous_gpu_time = 0, previous_time = 0;\n\n    std::vector<uint64_t> xe_fdinfo_last_cycles;\n    std::map<std::string, std::pair<uint64_t, uint64_t>> prev_xe_cycles;\n    int get_xe_load();\n\n    float get_memory_used();\n\n    void find_hwmon_sensors();\n    std::string find_hwmon_dir();\n    std::string find_hwmon_sensor_dir(std::string name);\n    void get_current_hwmon_readings();\n\n    float get_power_usage();\n    float last_power = 0;\n\n    std::ifstream gpu_clock_stream;\n    void find_i915_gt_dir();\n    void find_xe_gt_dir();\n    int get_gpu_clock();\n\n    uint64_t get_gpu_time_panfrost();\n    int get_gpu_clock_mali();\n\n    std::ifstream throttle_status_stream;\n    std::vector<std::ifstream> throttle_power_streams;\n    std::vector<std::ifstream> throttle_current_streams;\n    std::vector<std::ifstream> throttle_temp_streams;\n    bool check_throttle_reasons(std::vector<std::ifstream> &throttle_reason_streams);\n    int get_throttling_status();\n\n    const std::vector<std::string> intel_throttle_power = {\"reason_pl1\", \"reason_pl2\"};\n    const std::vector<std::string> intel_throttle_current = {\"reason_pl4\", \"reason_vr_tdc\"};\n    const std::vector<std::string> intel_throttle_temp = {\n        \"reason_prochot\", \"reason_ratl\", \"reason_thermal\", \"reason_vr_thermalert\"};\n    void load_xe_i915_throttle_reasons(\n        std::string throttle_folder,\n        std::vector<std::string> throttle_reasons,\n        std::vector<std::ifstream> &throttle_reason_streams);\n\n    std::map<std::string, std::ifstream> kgsl_streams;\n    void init_kgsl();\n    int get_kgsl_load();\n    int get_kgsl_temp();\n\npublic:\n    GPU_fdinfo(\n        const std::string module, const std::string pci_dev, const std::string drm_node,\n        const bool called_from_amdgpu_cpp=false\n    )\n        : module(module)\n        , pci_dev(pci_dev)\n        , drm_node(drm_node)\n    {\n        SPDLOG_DEBUG(\"GPU driver is \\\"{}\\\"\", module);\n\n        find_fd();\n        gather_fdinfo_data();\n\n        if (module == \"i915\") {\n            drm_engine_type = \"drm-engine-render\";\n            drm_memory_type = \"drm-resident-local0\";\n        } else if (module == \"xe\") {\n            drm_engine_type = \"drm-total-cycles-rcs\";\n            drm_memory_type = \"drm-resident-vram0\";\n        } else if (module == \"amdgpu\") {\n            drm_engine_type = \"drm-engine-gfx\";\n            drm_memory_type = \"drm-memory-vram\";\n        } else if (module == \"msm_dpu\") {\n            // msm driver does not report vram usage\n            drm_engine_type = \"drm-engine-gpu\";\n        } else if (module == \"msm_drm\") {\n            init_kgsl();\n        } else if (module == \"panfrost\") {\n            drm_engine_type = \"drm-engine-fragment\";\n            drm_memory_type = \"drm-resident-memory\";\n        } else if (module == \"panthor\") {\n            drm_engine_type = \"drm-engine-panthor\";\n            drm_memory_type = \"drm-resident-memory\";\n        }\n\n        if (fdinfo_data.size() > 0 &&\n            fdinfo_data[0].find(drm_memory_type) == fdinfo_data[0].end())\n        {\n            auto old_type = drm_memory_type;\n\n            if (module == \"i915\")\n                drm_memory_type = \"drm-resident-system0\";\n            else if (module == \"xe\")\n                drm_memory_type = \"drm-resident-gtt\";\n\n            SPDLOG_DEBUG(\n                \"\\\"{}\\\" is not found, you probably have an integrated GPU. \"\n                \"Using \\\"{}\\\"\", old_type, drm_memory_type\n            );\n        }\n\n        SPDLOG_DEBUG(\n            \"drm_engine_type = {}, drm_memory_type = {}\",\n            drm_engine_type, drm_memory_type\n        );\n\n        if (called_from_amdgpu_cpp)\n            return;\n\n        // i915: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon\n        // xe  : Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon\n\n        if (module == \"i915\") {\n            hwmon_sensors[\"voltage\"]     = { .rx = std::regex(\"in(0)_input\") };\n            hwmon_sensors[\"fan_speed\"]   = { .rx = std::regex(\"fan(1)_input\") };\n            hwmon_sensors[\"temp\"]        = { .rx = std::regex(\"temp(1)_input\") };\n            hwmon_sensors[\"energy\"]      = { .rx = std::regex(\"energy(1)_input\") };\n            hwmon_sensors[\"power_limit\"] = { .rx = std::regex(\"power(1)_max\") };\n        } else if (module == \"xe\") {\n            hwmon_sensors[\"voltage\"]     = { .rx = std::regex(\"in(1)_input\") };\n            // technically, there are 3 fan sensors, but just pick first one\n            hwmon_sensors[\"fan_speed\"]   = { .rx = std::regex(\"fan(1)_input\") };\n            hwmon_sensors[\"temp\"]        = { .rx = std::regex(\"temp(2)_input\") };\n            hwmon_sensors[\"vram_temp\"]   = { .rx = std::regex(\"temp(3)_input\") };\n            hwmon_sensors[\"energy\"]    = { .rx = std::regex(\"energy(2)_input\") };\n            hwmon_sensors[\"power_limit\"] = { .rx = std::regex(\"power(2)_max\") };\n        } else {\n            // For everyone else just guess\n            hwmon_sensors[\"voltage\"]   = { .rx = std::regex(\"in(\\\\d+)_input\") };\n            hwmon_sensors[\"fan_speed\"] = { .rx = std::regex(\"fan(\\\\d+)_input\") };\n            hwmon_sensors[\"temp\"]      = { .rx = std::regex(\"temp(\\\\d+)_input\") };\n            hwmon_sensors[\"power\"]     = { .rx = std::regex(\"power(\\\\d+)_input\") };\n            hwmon_sensors[\"energy\"]    = { .rx = std::regex(\"energy(\\\\d+)_input\") };\n        }\n\n        find_hwmon_sensors();\n\n        if (module == \"i915\")\n            find_i915_gt_dir();\n        else if (module == \"xe\")\n            find_xe_gt_dir();\n\n        thread = std::thread(&GPU_fdinfo::main_thread, this);\n        // \"mangohud-gpufdinfo\" wouldn't fit in the 15 byte limit\n        pthread_setname_np(thread.native_handle(), \"mangohud-gpufd\");\n    }\n\n    ~GPU_fdinfo() {\n        stop_thread = true;\n        if (thread.joinable())\n            thread.join();\n    }\n\n    gpu_metrics copy_metrics() const\n    {\n        return metrics;\n    };\n\n    void pause()\n    {\n        paused = true;\n        cond_var.notify_one();\n    }\n\n    void resume()\n    {\n        paused = false;\n        cond_var.notify_one();\n    }\n\n    float amdgpu_helper_get_proc_vram();\n};\n"
  },
  {
    "path": "src/gpu_metrics_util.h",
    "content": "#pragma once\n#include <atomic>\n\nstruct gpu_metrics {\n    int load;\n    int temp;\n    int junction_temp {-1};\n    int memory_temp {-1};\n    float sys_vram_used;\n    float proc_vram_used;\n    float memoryTotal;\n    int MemClock;\n    int CoreClock;\n    float powerUsage;\n    float powerLimit;\n    float apu_cpu_power;\n    int apu_cpu_temp;\n    bool is_power_throttled;\n    bool is_current_throttled;\n    bool is_temp_throttled;\n    bool is_other_throttled;\n    float gtt_used;\n    int fan_speed;\n    int voltage;\n    bool fan_rpm;\n\n    gpu_metrics()\n        : load(0), temp(0), junction_temp(0), memory_temp(0),\n          sys_vram_used(0.0f), proc_vram_used(0.0f), memoryTotal(0.0f), MemClock(0), CoreClock(0),\n          powerUsage(0.0f), powerLimit(0.0f), apu_cpu_power(0.0f), apu_cpu_temp(0),\n          is_power_throttled(false), is_current_throttled(false),\n          is_temp_throttled(false), is_other_throttled(false),\n          gtt_used(0.0f), fan_speed(0), voltage(0), fan_rpm(false) {}\n};\n\n#define METRICS_UPDATE_PERIOD_MS 500\n#define METRICS_POLLING_PERIOD_MS 25\n#define METRICS_SAMPLE_COUNT (METRICS_UPDATE_PERIOD_MS/METRICS_POLLING_PERIOD_MS)\n\n#define GPU_UPDATE_METRIC_AVERAGE(FIELD) do { int value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0)\n#define GPU_UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0)\n#define GPU_UPDATE_METRIC_MAX(FIELD) do { int cur_max = metrics_buffer[0].FIELD; for (size_t s=1; s < METRICS_SAMPLE_COUNT; s++) { cur_max = MAX(cur_max, metrics_buffer[s].FIELD); }; metrics.FIELD = cur_max; } while(0)\n#define GPU_UPDATE_METRIC_LAST(FIELD) do { metrics.FIELD = metrics_buffer[METRICS_SAMPLE_COUNT - 1].FIELD; } while(0)\n\nclass Throttling {\n\tpublic:\n\t\tstd::vector<float> power;\n\t\tstd::vector<float> thermal;\n\t\tint64_t indep_throttle_status = 0;\n        bool use_v3;\n        std::atomic<bool> v3_power {false};\n        std::atomic<bool> v3_thermal {false};\n        uint32_t vendor_id;\n        // CORE, HOTSPOT, SOC bits\n        // trying to roughly match the bits that are exposed in v3\n        uint64_t indep_temp_mask = ((1ULL << 33) | (1ULL << 36) | (1ULL << 37));\n\n\t\tThrottling(uint32_t vendor_id)\n\t\t\t: power(200, 0.0f),\n\t\t\tthermal(200, 0.0f), vendor_id(vendor_id) {}\n\n\t\tvoid update(){\n            if (vendor_id == 0x10de) {\n                if (vendor_id == 0x10de && use_v3) {\n                    power.push_back(v3_power.load() ? 0.1f : 0.0f);\n                    thermal.push_back(v3_thermal.load() ? 0.1f : 0.0f);\n                } else {\n                    power.push_back((indep_throttle_status & (1ULL << 4)) != 0 ? 0.1f : 0.0f);\n                    thermal.push_back((indep_throttle_status & indep_temp_mask) != 0 ? 0.1f : 0.0f);\n                }\n            } else if (vendor_id == 0x1002) {\n                power.push_back(((indep_throttle_status >> 0 & 0xFF) != 0) ? 0.1f : 0.0f);\n                thermal.push_back(((indep_throttle_status >> 32 & 0xFFFF) != 0) ? 0.1f : 0.0f );\n            }\n\n\t\t\tpower.erase(power.begin());\n\t\t\tthermal.erase(thermal.begin());\n\t\t}\n        \n\t\tbool power_throttling(){\n            return std::find(power.begin(), power.end(), 0.1f) != power.end();\n\t\t}\n        \n\t\tbool thermal_throttling(){\n            return std::find(thermal.begin(), thermal.end(), 0.1f) != thermal.end();\n\t\t}\n};\n"
  },
  {
    "path": "src/hud_elements.cpp",
    "content": "#include <spdlog/spdlog.h>\n#include <algorithm>\n#include <functional>\n#include <sstream>\n#include <cmath>\n#include <map>\n#include \"overlay.h\"\n#include \"overlay_params.h\"\n#include \"hud_elements.h\"\n#include \"logging.h\"\n#include \"battery.h\"\n#include \"device.h\"\n#include \"cpu.h\"\n#include \"gpu.h\"\n#include \"memory.h\"\n#include \"iostats.h\"\n#include \"mesa/util/macros.h\"\n#include \"string_utils.h\"\n#include \"app/mangoapp.h\"\n#include <IconsForkAwesome.h>\n#include \"version.h\"\n#include \"blacklist.h\"\n#ifdef __linux__\n#include \"implot.h\"\n#endif\n#include \"amdgpu.h\"\n#include \"fps_metrics.h\"\n#include \"fex.h\"\n#include \"ftrace.h\"\n#include \"winesync.h\"\n#include \"fps_limiter.h\"\n\n#define CHAR_CELSIUS    \"\\xe2\\x84\\x83\"\n#define CHAR_FAHRENHEIT \"\\xe2\\x84\\x89\"\n\nusing namespace std;\n\n// Cut from https://github.com/ocornut/imgui/pull/2943\n// Probably move to ImGui\nstatic float SRGBToLinear(float in)\n{\n    if (in <= 0.04045f)\n        return in / 12.92f;\n    else\n        return powf((in + 0.055f) / 1.055f, 2.4f);\n}\n\nstatic ImVec4 SRGBToLinear(ImVec4 col)\n{\n    col.x = SRGBToLinear(col.x);\n    col.y = SRGBToLinear(col.y);\n    col.z = SRGBToLinear(col.z);\n    // Alpha component is already linear\n\n    return col;\n}\n\nstatic float LinearToPQ(float in)\n{\n    const float m1 = 0.1593017578125f;\n    const float m2 = 78.84375f;\n    const float c1 = 0.8359375f;\n    const float c2 = 18.8515625f;\n    const float c3 = 18.6875f;\n    /* target 200 cd/m^2 as our maximum rather than 10000 cd/m^2 */\n    const float targetL = 200.f;\n    const float maxL = 10000.0f;\n\n    in = powf(in * (targetL / maxL), m1);\n    in = (c1 + c2 * in) / (1.0f + c3 * in);\n    return powf(in, m2);\n}\n\nstatic double dot(const ImVec4& a, const ImVec4& b)\n{\n    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;\n}\n\nstatic ImVec4 SRGBtoBT2020(ImVec4 col)\n{\n    const ImVec4 to2020[4] = {\n        {0.627392, 0.32903, 0.0432691, 0.0},\n        {0.0691229, 0.9195232, 0.0113204, 0.0},\n        {0.0164229, 0.088042, 0.8956166, 0.0},\n        {0.0, 0.0, 0.0, 1.0}\n    };\n\n    col.x = dot(to2020[0], col);\n    col.y = dot(to2020[1], col);\n    col.z = dot(to2020[2], col);\n    col.w = dot(to2020[3], col);\n\n    return col;\n}\n\nstatic ImVec4 LinearToPQ(ImVec4 col)\n{\n    col = SRGBtoBT2020(col);\n\n    col.x = LinearToPQ(col.x);\n    col.y = LinearToPQ(col.y);\n    col.z = LinearToPQ(col.z);\n\n    return col;\n}\n\nstatic float LinearToHLG(float in)\n{\n    const float a = 0.17883277f;\n    const float b = 0.28466892f;\n    const float c = 0.55991073f;\n\n    if (in <= 1.0f/12.0f)\n        return sqrtf(3.0f * in);\n    else\n        return a * logf(12.0f * in - b) + c;\n}\n\nstatic ImVec4 LinearToHLG(ImVec4 col)\n{\n    col = SRGBtoBT2020(col);\n\n    col.x = LinearToHLG(col.x);\n    col.y = LinearToHLG(col.y);\n    col.z = LinearToHLG(col.z);\n\n    return col;\n}\n\ntemplate<typename T, typename R = float>\nR format_units(T value, const char*& unit)\n{\n    static const char* const units[] = {\"B\", \"KiB\", \"MiB\", \"GiB\", \"TiB\", \"PiB\", \"EiB\", \"ZiB\"};\n    size_t u = 0;\n    R out_value = value;\n    while (out_value > 1023 && u < ARRAY_SIZE(units)) {\n        out_value /= 1024;\n        ++u;\n    }\n    unit = units[u];\n    return out_value;\n}\n\nvoid HudElements::convert_colors(const struct overlay_params& params)\n{\n    HUDElements.colors.update = false;\n    auto convert = [&params](unsigned color) -> ImVec4 {\n        ImVec4 fc = ImGui::ColorConvertU32ToFloat4(color);\n        fc.w = params.alpha;\n        if (HUDElements.colors.convert)\n        {\n            switch (params.transfer_function)\n            {\n                case PQ:\n                    fc = SRGBToLinear(fc);\n                    return LinearToPQ(fc);\n                case HLG:\n                    fc = SRGBToLinear(fc);\n                    return LinearToHLG(fc);\n                case SRGB:\n                    return SRGBToLinear(fc);\n                default: break;\n            }\n        }\n        return fc;\n    };\n\n    HUDElements.colors.cpu = convert(params.cpu_color);\n    HUDElements.colors.gpu = convert(params.gpu_color);\n    HUDElements.colors.vram = convert(params.vram_color);\n    HUDElements.colors.ram = convert(params.ram_color);\n    HUDElements.colors.engine = convert(params.engine_color);\n    HUDElements.colors.io = convert(params.io_color);\n    HUDElements.colors.frametime = convert(params.frametime_color);\n    HUDElements.colors.background = convert(params.background_color);\n    HUDElements.colors.text = convert(params.text_color);\n    HUDElements.colors.media_player = convert(params.media_player_color);\n    HUDElements.colors.wine = convert(params.wine_color);\n    HUDElements.colors.horizontal_separator = convert(params.horizontal_separator_color);\n    HUDElements.colors.battery = convert(params.battery_color);\n    HUDElements.colors.gpu_load_low = convert(params.gpu_load_color[0]);\n    HUDElements.colors.gpu_load_med = convert(params.gpu_load_color[1]);\n    HUDElements.colors.gpu_load_high = convert(params.gpu_load_color[2]);\n    HUDElements.colors.cpu_load_low = convert(params.cpu_load_color[0]);\n    HUDElements.colors.cpu_load_med = convert(params.cpu_load_color[1]);\n    HUDElements.colors.cpu_load_high = convert(params.cpu_load_color[2]);\n    HUDElements.colors.fps_value_low = convert(params.fps_color[0]);\n    HUDElements.colors.fps_value_med = convert(params.fps_color[1]);\n    HUDElements.colors.fps_value_high = convert(params.fps_color[2]);\n    HUDElements.colors.text_outline = convert(params.text_outline_color);\n    HUDElements.colors.network = convert(params.network_color);\n\n    ImGuiStyle& style = ImGui::GetStyle();\n    style.Colors[ImGuiCol_PlotLines] = convert(params.frametime_color);\n    style.Colors[ImGuiCol_PlotHistogram] = convert(params.frametime_color);\n    style.Colors[ImGuiCol_WindowBg]  = convert(params.background_color);\n    style.Colors[ImGuiCol_Text] = convert(params.text_color);\n    style.CellPadding.y = params.cellpadding_y * real_font_size.y;\n    style.WindowRounding = params.round_corners;\n    style.AntiAliasedLines = false;\n}\n\nvoid HudElements::convert_colors(bool do_conv, const struct overlay_params& params)\n{\n    HUDElements.colors.convert = do_conv;\n    convert_colors(params);\n}\n\nvoid HudElements::TextColored(ImVec4 col, const char *fmt, ...){\n    auto textColor = ImGui::ColorConvertFloat4ToU32(col);\n    char buffer[128] {};\n\n    va_list args;\n    va_start(args, fmt);\n    vsnprintf(buffer, sizeof(buffer), fmt, args);\n    va_end(args);\n\n    RenderOutlinedText(buffer, textColor);\n}\n\nint HudElements::convert_to_fahrenheit(int celsius){\n    int fahrenheit = (celsius * 9 / 5) + 32;\n    return fahrenheit;\n}\n\nstatic void ImguiNextColumnFirstItem()\n{\n    ImGui::TableNextColumn();\n    HUDElements.table_columns_count += 1;\n}\n/**\n* Go to next column or second column on new row\n*/\nstatic void ImguiNextColumnOrNewRow(int column = -1)\n{\n    if (column > -1 && column < ImGui::TableGetColumnCount())\n        ImGui::TableSetColumnIndex(column);\n    else\n    {\n        ImGui::TableNextColumn();\n        HUDElements.table_columns_count += 1;\n        if (ImGui::TableGetColumnIndex() == 0 && ImGui::TableGetColumnCount() > 1) {\n            ImGui::TableNextColumn();\n            HUDElements.table_columns_count += 1;\n        }\n    }\n}\n\nstatic bool ImGuiTextOverflow(const char* text) {\n    return ImGui::CalcTextSize(text).x > ImGui::CalcItemWidth() + HUDElements.ralign_width / 2;\n}\n// This function is only used in battery and battery is not used in windows builds\n// Battery should probably be reworked to not use this func since nothing else needs it\n#ifdef __linux__\nstatic void ImGuiTableSetColumnIndex(int column)\n{\n    ImGui::TableSetColumnIndex(std::max(0, std::min(column, ImGui::TableGetColumnCount() - 1)));\n}\n#endif\n\nvoid HudElements::time(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time]){\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] &&\n            !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] &&\n            !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time_no_label]){\n            ImguiNextColumnFirstItem();\n            HUDElements.TextColored(HUDElements.colors.text, \"Time\");\n            ImguiNextColumnOrNewRow();\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", HUDElements.sw_stats->time.c_str());\n        } else {\n            ImguiNextColumnFirstItem();\n            HUDElements.TextColored(HUDElements.colors.text, \"%s\", HUDElements.sw_stats->time.c_str());\n        }\n    }\n}\n\nvoid HudElements::version(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_version]){\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.text, \"%s\", MANGOHUD_VERSION);\n    }\n}\n\nvoid HudElements::gpu_stats(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] && gpus){\n        for (auto& gpu : gpus->selected_gpus()) {\n            ImguiNextColumnFirstItem();\n            HUDElements.TextColored(HUDElements.colors.gpu, \"%s\", gpu->gpu_text().c_str());\n\n            ImguiNextColumnOrNewRow();\n            auto text_color = HUDElements.colors.text;\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_load_change]){\n                struct LOAD_DATA gpu_data = {\n                    HUDElements.colors.gpu_load_low,\n                    HUDElements.colors.gpu_load_med,\n                    HUDElements.colors.gpu_load_high,\n                    HUDElements.params->gpu_load_value[0],\n                    HUDElements.params->gpu_load_value[1]\n                };\n\n                auto load_color = change_on_load_temp(gpu_data, gpu->metrics.load);\n                right_aligned_text(load_color, HUDElements.ralign_width, \"%i\", gpu->metrics.load);\n                ImGui::SameLine(0, 1.0f);\n                HUDElements.TextColored(load_color,\"%%\");\n            }\n            else {\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.load);\n                ImGui::SameLine(0, 1.0f);\n                HUDElements.TextColored(text_color,\"%%\");\n                // ImGui::SameLine(150);\n                // ImGui::Text(\"%s\", \"%\");\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp]){\n                ImguiNextColumnOrNewRow();\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", HUDElements.convert_to_fahrenheit(gpu->metrics.temp));\n                else\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.temp);\n                ImGui::SameLine(0, 1.0f);\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact])\n                    HUDElements.TextColored(HUDElements.colors.text, \"°\");\n                else\n                    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                        HUDElements.TextColored(HUDElements.colors.text, \"°F\");\n                    else\n                        HUDElements.TextColored(HUDElements.colors.text, \"°C\");\n            }\n\n            if (gpu->metrics.junction_temp > -1 && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_junction_temp]) {\n                ImguiNextColumnOrNewRow();\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", HUDElements.convert_to_fahrenheit(gpu->metrics.junction_temp));\n                else\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.junction_temp);\n                ImGui::SameLine(0, 1.0f);\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                    HUDElements.TextColored(HUDElements.colors.text, \"°F\");\n                else\n                    HUDElements.TextColored(HUDElements.colors.text, \"°C\");\n                ImGui::SameLine(0, 1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                HUDElements.TextColored(HUDElements.colors.text, \"Jnc\");\n                ImGui::PopFont();\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] && !gpu->is_apu()){\n                ImguiNextColumnOrNewRow();\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.fan_speed);\n                ImGui::SameLine(0, 1.0f);\n                if (gpu->metrics.fan_rpm) {\n                    ImGui::PushFont(HUDElements.sw_stats->font_small);\n                    HUDElements.TextColored(HUDElements.colors.text, \"RPM\");\n                } else {\n                    HUDElements.TextColored(HUDElements.colors.text, \"%%\");\n                    ImGui::PushFont(HUDElements.sw_stats->font_small);\n                    ImGui::SameLine(0, 1.0f);\n                    HUDElements.TextColored(HUDElements.colors.text, \"FAN\");\n                }\n                ImGui::PopFont();\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock]){\n                ImguiNextColumnOrNewRow();\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.CoreClock);\n                ImGui::SameLine(0, 1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                HUDElements.TextColored(HUDElements.colors.text, \"MHz\");\n                ImGui::PopFont();\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_power]) {\n                ImguiNextColumnOrNewRow();\n                char str[16];\n                snprintf(str, sizeof(str), \"%.1f\", gpu->metrics.powerUsage);\n                if (strlen(str) > 4)\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%.0f\", gpu->metrics.powerUsage);\n                else\n                    right_aligned_text(text_color, HUDElements.ralign_width, \"%.1f\", gpu->metrics.powerUsage);\n                ImGui::SameLine(0, 1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_power_limit])\n                    HUDElements.TextColored(HUDElements.colors.text, \"/%.0fW\", gpu->metrics.powerLimit);\n                else\n                    HUDElements.TextColored(HUDElements.colors.text, \"W\");\n                ImGui::PopFont();\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_efficiency]) {\n                ImguiNextColumnOrNewRow();\n                float efficiency;\n                const char* efficiency_unit;\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_flip_efficiency]) {\n                    efficiency=gpu->metrics.powerUsage/HUDElements.sw_stats->fps;\n                    efficiency_unit=\"J/F\";\n                } else {\n                    efficiency=HUDElements.sw_stats->fps/gpu->metrics.powerUsage;\n                    efficiency_unit=\"F/J\";\n                }\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%.2f\", efficiency);\n                ImGui::SameLine(0, 1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                HUDElements.TextColored(HUDElements.colors.text, efficiency_unit);\n                ImGui::PopFont();\n            }\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_voltage]) {\n                ImguiNextColumnOrNewRow();\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", gpu->metrics.voltage);\n                ImGui::SameLine(0, 1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                HUDElements.TextColored(HUDElements.colors.text, \"mV\");\n                ImGui::PopFont();\n            }\n            if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n                ImGui::TableNextRow();\n        }\n    }\n}\n\nvoid HudElements::cpu_stats(){\n    if(HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats]){\n        ImguiNextColumnFirstItem();\n        const char* cpu_text;\n        if (HUDElements.params->cpu_text.empty())\n            cpu_text = \"CPU\";\n        else\n            cpu_text = HUDElements.params->cpu_text.c_str();\n\n        HUDElements.TextColored(HUDElements.colors.cpu, \"%s\", cpu_text);\n        ImguiNextColumnOrNewRow();\n        auto text_color = HUDElements.colors.text;\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_load_change]){\n            int cpu_load_percent = int(cpuStats.GetCPUDataTotal().percent);\n            struct LOAD_DATA cpu_data = {\n                HUDElements.colors.cpu_load_low,\n                HUDElements.colors.cpu_load_med,\n                HUDElements.colors.cpu_load_high,\n                HUDElements.params->cpu_load_value[0],\n                HUDElements.params->cpu_load_value[1]\n            };\n\n            auto load_color = change_on_load_temp(cpu_data, cpu_load_percent);\n            right_aligned_text(load_color, HUDElements.ralign_width, \"%d\", cpu_load_percent);\n            ImGui::SameLine(0, 1.0f);\n            HUDElements.TextColored(load_color, \"%%\");\n        }\n        else {\n            right_aligned_text(text_color, HUDElements.ralign_width, \"%d\", int(cpuStats.GetCPUDataTotal().percent));\n            ImGui::SameLine(0, 1.0f);\n            HUDElements.TextColored(HUDElements.colors.text, \"%%\");\n        }\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp]){\n            ImguiNextColumnOrNewRow();\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", HUDElements.convert_to_fahrenheit(cpuStats.GetCPUDataTotal().temp));\n            else\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", cpuStats.GetCPUDataTotal().temp);\n            ImGui::SameLine(0, 1.0f);\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact])\n                HUDElements.TextColored(HUDElements.colors.text, \"°\");\n            else\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                    HUDElements.TextColored(HUDElements.colors.text, \"°F\");\n                else\n                    HUDElements.TextColored(HUDElements.colors.text, \"°C\");\n        }\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz]){\n            ImguiNextColumnOrNewRow();\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", cpuStats.GetCPUDataTotal().cpu_mhz);\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"MHz\");\n            ImGui::PopFont();\n        }\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_power]){\n            ImguiNextColumnOrNewRow();\n            char str[16];\n            snprintf(str, sizeof(str), \"%.1f\", cpuStats.GetCPUDataTotal().power);\n            if (strlen(str) > 4)\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", cpuStats.GetCPUDataTotal().power);\n            else\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", cpuStats.GetCPUDataTotal().power);\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"W\");\n            ImGui::PopFont();\n        }\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_efficiency]) {\n            ImguiNextColumnOrNewRow();\n            float efficiency;\n            const char* efficiency_unit;\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_flip_efficiency]) {\n                efficiency=cpuStats.GetCPUDataTotal().power/HUDElements.sw_stats->fps;\n                efficiency_unit=\"J/F\";\n            } else {\n                efficiency=HUDElements.sw_stats->fps/cpuStats.GetCPUDataTotal().power;\n                efficiency_unit=\"F/J\";\n            }\n            right_aligned_text(text_color, HUDElements.ralign_width, \"%.2f\", efficiency);\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, efficiency_unit);\n            ImGui::PopFont();\n        }\n    }\n}\n\n\nstatic float get_core_load_stat(void*,int);\nstatic float get_core_load_stat(void *data, int idx){\n    return ((CPUStats *)data)->GetCPUData().at(idx).percent;\n}\n\nvoid HudElements::core_load(){\n    if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_load])\n        return;\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_bars]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            HUDElements.TextColored(HUDElements.colors.cpu, \"CPU Cores\");\n            ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            ImguiNextColumnFirstItem();\n        }\n        char hash[40];\n        snprintf(hash, sizeof(hash), \"##%s\", overlay_param_names[OVERLAY_PARAM_ENABLED_core_bars]);\n        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n        float width, height = 0;\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]){\n            width = 150;\n            height = HUDElements.params->font_size;\n        } else {\n            width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x);\n            height = 50;\n        }\n\n        if (ImGui::BeginChild(\"core_bars_window\", ImVec2(width, height))) {\n            ImGui::PlotHistogram(hash, get_core_load_stat, &cpuStats,\n                                cpuStats.GetCPUData().size(), 0,\n                                NULL, 0.0, 100.0,\n                                ImVec2(width, height));\n        }\n        ImGui::EndChild();\n        ImGui::PopFont();\n        ImGui::PopStyleColor();\n    } else {\n        for (const CPUData &cpuData : cpuStats.GetCPUData())\n        {\n            ImguiNextColumnFirstItem();\n            HUDElements.TextColored(HUDElements.colors.cpu, \"CPU\");\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_type])\n                HUDElements.TextColored(HUDElements.colors.cpu, cpuData.label.c_str());\n            else\n                HUDElements.TextColored(HUDElements.colors.cpu, \"%i\", cpuData.cpu_id);\n\n            ImGui::PopFont();\n            ImguiNextColumnOrNewRow();\n            auto text_color = HUDElements.colors.text;\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_load_change]){\n                int cpu_load_percent = int(cpuData.percent);\n                struct LOAD_DATA cpu_data = {\n                    HUDElements.colors.cpu_load_low,\n                    HUDElements.colors.cpu_load_med,\n                    HUDElements.colors.cpu_load_high,\n                    HUDElements.params->cpu_load_value[0],\n                    HUDElements.params->cpu_load_value[1]\n                };\n                auto load_color = change_on_load_temp(cpu_data, cpu_load_percent);\n                right_aligned_text(load_color, HUDElements.ralign_width, \"%d\", cpu_load_percent);\n                ImGui::SameLine(0, 1.0f);\n                HUDElements.TextColored(load_color, \"%%\");\n                ImguiNextColumnOrNewRow();\n            }\n            else {\n                right_aligned_text(text_color, HUDElements.ralign_width, \"%i\", int(cpuData.percent));\n                ImGui::SameLine(0, 1.0f);\n                HUDElements.TextColored(HUDElements.colors.text, \"%%\");\n                ImguiNextColumnOrNewRow();\n            }\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", cpuData.mhz);\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"MHz\");\n            ImGui::PopFont();\n        }\n    }\n}\n\nvoid HudElements::io_stats(){\n#ifndef _WIN32\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] || HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]){\n        ImguiNextColumnFirstItem();\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write])\n            HUDElements.TextColored(HUDElements.colors.io, \"IO RD\");\n        else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write])\n            HUDElements.TextColored(HUDElements.colors.io, \"IO RW\");\n        else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read])\n            HUDElements.TextColored(HUDElements.colors.io, \"IO WR\");\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read]){\n            ImguiNextColumnOrNewRow();\n            const float val = g_io_stats.per_second.read;\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, val < 100 ? \"%.1f\" : \"%.f\", val);\n            ImGui::SameLine(0,1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"MiB/s\");\n            ImGui::PopFont();\n        }\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]){\n            ImguiNextColumnOrNewRow();\n            const float val = g_io_stats.per_second.write;\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, val < 100 ? \"%.1f\" : \"%.f\", val);\n            ImGui::SameLine(0,1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"MiB/s\");\n            ImGui::PopFont();\n        }\n    }\n#endif\n}\n\nvoid HudElements::vram(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vram] && gpus){\n        size_t i = 0;\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats]){\n            for (auto& gpu : gpus->selected_gpus()) {\n                ImguiNextColumnFirstItem();\n                // Just iterate through the user selected GPUs\n                if (!HUDElements.params->gpu_list.empty())\n                    for (auto& gpu_index : HUDElements.params->gpu_list)\n                        if (gpu_index < gpus->available_gpus.size())\n                            if (i != gpu_index)\n                                continue;\n\n\n                HUDElements.TextColored(HUDElements.colors.vram, gpu->vram_text().c_str());\n\n                ImguiNextColumnOrNewRow();\n                // Add gtt_used to vram usage for APUs\n                if (gpu->is_apu())\n                    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", gpu->metrics.sys_vram_used + gpu->metrics.gtt_used);\n                else\n                    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", gpu->metrics.sys_vram_used);\n                if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n                    ImGui::SameLine(0,1.0f);\n                    ImGui::PushFont(HUDElements.sw_stats->font_small);\n                    HUDElements.TextColored(HUDElements.colors.text, \"GiB\");\n                    ImGui::PopFont();\n                }\n\n                if (gpu->metrics.memory_temp > -1 && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp]) {\n                    ImguiNextColumnOrNewRow();\n                    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", HUDElements.convert_to_fahrenheit(gpu->metrics.memory_temp));\n                    else\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", gpu->metrics.memory_temp);\n                    ImGui::SameLine(0, 1.0f);\n                    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n                        HUDElements.TextColored(HUDElements.colors.text, \"°F\");\n                    else\n                        HUDElements.TextColored(HUDElements.colors.text, \"°C\");\n                }\n\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock]){\n                    ImguiNextColumnOrNewRow();\n                    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", gpu->metrics.MemClock);\n                    ImGui::SameLine(0, 1.0f);\n                    ImGui::PushFont(HUDElements.sw_stats->font_small);\n                    HUDElements.TextColored(HUDElements.colors.text, \"MHz\");\n                    ImGui::PopFont();\n                }\n                if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n                    ImGui::TableNextRow();\n                i++;\n            }\n        }\n    }\n}\n\nvoid HudElements::proc_vram() {\n    if (\n        !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_proc_vram] ||\n        !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats]\n    )\n        return;\n\n    if (!gpus)\n        return;\n\n    size_t idx = 0;\n    for (const std::shared_ptr<GPU>& gpu : gpus->selected_gpus()) {\n        ImguiNextColumnFirstItem();\n\n        if (gpus->selected_gpus().size() > 1)\n            HUDElements.TextColored(HUDElements.colors.vram, \"PVRAM%i\", idx++);\n        else\n            HUDElements.TextColored(HUDElements.colors.vram, \"PVRAM\");\n\n        ImguiNextColumnOrNewRow();\n\n        right_aligned_text(\n            HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", gpu->metrics.proc_vram_used\n        );\n\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) {\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"GiB\");\n            ImGui::PopFont();\n        }\n\n        // show only if vram is not enabled\n        if (\n            !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vram] &&\n            HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp]\n        ) {\n            ImguiNextColumnOrNewRow();\n\n            int temp;\n            std::string unit;\n\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) {\n                temp = HUDElements.convert_to_fahrenheit(gpu->metrics.memory_temp);\n                unit = \"°F\";\n            } else {\n                temp = gpu->metrics.memory_temp;\n                unit = \"°C\";\n            }\n\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", temp);\n\n            ImGui::SameLine(0, 1.0f);\n\n            HUDElements.TextColored(HUDElements.colors.text, unit.c_str());\n        }\n\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n            ImGui::TableNextRow();\n    }\n}\n\nvoid HudElements::ram(){\n#ifdef __linux__\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram] ||\n        HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram_temp]) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.ram, \"RAM\");\n    }\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram]) {\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", memused);\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"GiB\");\n            ImGui::PopFont();\n        }\n    }\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_swap]){\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", swapused);\n        ImGui::SameLine(0, 1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"GiB\");\n        ImGui::PopFont();\n    }\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram_temp]) {\n        ImguiNextColumnOrNewRow();\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", HUDElements.convert_to_fahrenheit(mem_temp));\n        else\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", mem_temp);\n        ImGui::SameLine(0, 1.0f);\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact])\n            HUDElements.TextColored(HUDElements.colors.text, \"°\");\n        else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit])\n            HUDElements.TextColored(HUDElements.colors.text, \"°F\");\n        else\n            HUDElements.TextColored(HUDElements.colors.text, \"°C\");\n    }\n#endif\n}\n\nvoid HudElements::procmem()\n{\n#ifdef __linux__\n    const char* unit = nullptr;\n\n    if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem])\n        return;\n\n    ImguiNextColumnFirstItem();\n    HUDElements.TextColored(HUDElements.colors.ram, \"PMEM\");\n    ImguiNextColumnOrNewRow();\n    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", format_units(proc_mem_resident, unit));\n    ImGui::SameLine(0, 1.0f);\n    ImGui::PushFont(HUDElements.sw_stats->font_small);\n    HUDElements.TextColored(HUDElements.colors.text, \"%s\", unit);\n    ImGui::PopFont();\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_shared]) {\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", format_units(proc_mem_shared, unit));\n        ImGui::SameLine(0,1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"%s\", unit);\n        ImGui::PopFont();\n    }\n\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_virt]) {\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", format_units(proc_mem_virt, unit));\n        ImGui::SameLine(0, 1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"%s\", unit);\n        ImGui::PopFont();\n    }\n#endif\n}\n\nvoid HudElements::fps(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", engine_name(*HUDElements.sw_stats));\n\n        ImguiNextColumnOrNewRow();\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_color_change]){\n            int fps = int(HUDElements.sw_stats->fps);\n            struct LOAD_DATA fps_data = {\n            HUDElements.colors.fps_value_low,\n            HUDElements.colors.fps_value_med,\n            HUDElements.colors.fps_value_high,\n            HUDElements.params->fps_value[0],\n            HUDElements.params->fps_value[1]\n            };\n            auto load_color = change_on_load_temp(fps_data, fps);\n            right_aligned_text(load_color, HUDElements.ralign_width, \"%.0f\", HUDElements.sw_stats->fps);\n        }\n        else {\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", HUDElements.sw_stats->fps);\n        }\n        ImGui::SameLine(0, 1.0f);\n        if(!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript]){\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"FPS\");\n            ImGui::PopFont();\n        }\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frametime]){\n            ImguiNextColumnOrNewRow();\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", 1000 / HUDElements.sw_stats->fps);\n            ImGui::SameLine(0, 1.0f);\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.text, \"ms\");\n            ImGui::PopFont();\n        }\n    } else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_engine_version]){\n        ImguiNextColumnOrNewRow();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", HUDElements.sw_stats->engineName.c_str());\n    }\n}\n\nvoid HudElements::fps_only(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){\n        ImguiNextColumnFirstItem();\n        auto load_color = HUDElements.colors.text;\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_color_change]){\n            int fps = int(HUDElements.sw_stats->fps);\n            struct LOAD_DATA fps_data = {\n            HUDElements.colors.fps_value_low,\n            HUDElements.colors.fps_value_med,\n            HUDElements.colors.fps_value_high,\n            HUDElements.params->fps_value[0],\n            HUDElements.params->fps_value[1]\n            };\n            load_color = change_on_load_temp(fps_data, fps);\n        }\n        HUDElements.TextColored(load_color, \"%.0f\", HUDElements.sw_stats->fps);\n    }\n}\n\nvoid HudElements::gpu_name(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_name] && !HUDElements.sw_stats->gpuName.empty()){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine,\n            \"%s\", HUDElements.sw_stats->gpuName.c_str());\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::engine_version(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_engine_version]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        if (HUDElements.is_vulkan) {\n            if ((HUDElements.sw_stats->engine == EngineTypes::DXVK || HUDElements.sw_stats->engine == EngineTypes::VKD3D)){\n                HUDElements.TextColored(HUDElements.colors.engine,\n                    \"%s/%d.%d.%d\", HUDElements.sw_stats->engineVersion.c_str(),\n                    HUDElements.sw_stats->version_vk.major,\n                    HUDElements.sw_stats->version_vk.minor,\n                    HUDElements.sw_stats->version_vk.patch);\n            } else {\n                HUDElements.TextColored(HUDElements.colors.engine,\n                    \"%d.%d.%d\",\n                    HUDElements.sw_stats->version_vk.major,\n                    HUDElements.sw_stats->version_vk.minor,\n                    HUDElements.sw_stats->version_vk.patch);\n            }\n        } else {\n            HUDElements.TextColored(HUDElements.colors.engine,\n                \"%d.%d%s\", HUDElements.sw_stats->version_gl.major, HUDElements.sw_stats->version_gl.minor,\n                HUDElements.sw_stats->version_gl.is_gles ? \" ES\" : \"\");\n        }\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::vulkan_driver(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vulkan_driver] && !HUDElements.sw_stats->driverName.empty()){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine,\n            \"%s\", HUDElements.sw_stats->driverName.c_str());\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::arch(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_arch]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"\" MANGOHUD_ARCH);\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::wine(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_wine]){\n        ImguiNextColumnFirstItem();\n        if (!wineVersion.empty()){\n            ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n            HUDElements.TextColored(HUDElements.colors.wine, \"%s\", wineVersion.c_str());\n            ImGui::PopFont();\n        }\n    }\n}\n\nstatic inline double TransformForward_Custom(double v, void*) {\n    if (v > 50)\n        v = 49.9;\n\n    return v;\n}\n\nstatic inline double TransformInverse_Custom(double v, void*) {\n   return v;\n}\n\nvoid HudElements::frame_timing(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Frametime\");\n            ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            right_aligned_text(HUDElements.colors.text, ImGui::GetContentRegionAvail().x, \"min: %.1fms, max: %.1fms\", min_frametime, max_frametime);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            ImguiNextColumnFirstItem();\n        }\n        char hash[40];\n        snprintf(hash, sizeof(hash), \"##%s\", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]);\n        HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing;\n        HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */\n        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n        double min_time = 0.0f;\n        double max_time = 50.0f;\n        float width, height = 0;\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]){\n            width = 150;\n            height = HUDElements.params->font_size * 0.85;\n        } else {\n            width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x);\n            height = max_time;\n        }\n\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing]){\n            min_time = min_frametime;\n            max_time = max_frametime;\n        }\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed]){\n            height = 125;\n        }\n\n        if (ImGui::BeginChild(\"my_child_window\", ImVec2(width, height), false, ImGuiWindowFlags_NoDecoration)) {\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){\n                ImGui::PlotHistogram(hash, get_time_stat, HUDElements.sw_stats,\n                                    ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,\n                                    NULL, min_time, max_time,\n                                    ImVec2(width, height));\n            } else {\n#ifndef __linux__\n                ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats,\n                                ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,\n                                NULL, min_time, max_time,\n                                ImVec2(width, height));\n#else\n\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n                    ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats,\n                    ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0,\n                    NULL, min_time, max_time,\n                    ImVec2(width, height));\n                } else {\n                    if (ImPlot::BeginPlot(\"My Plot\", ImVec2(width, height), ImPlotFlags_CanvasOnly | ImPlotFlags_NoInputs)) {\n                        ImPlotStyle& style = ImPlot::GetStyle();\n                        style.Colors[ImPlotCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 0.00f);\n                        style.Colors[ImPlotCol_AxisGrid] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);\n                        style.Colors[ImPlotCol_AxisTick] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);\n                        ImPlotAxisFlags ax_flags_x = ImPlotAxisFlags_NoDecorations;\n                        ImPlotAxisFlags ax_flags_y = ImPlotAxisFlags_NoDecorations;\n                        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed])\n                            ax_flags_y = ImPlotAxisFlags_Opposite | ImPlotAxisFlags_NoMenus;\n\n                        ImPlot::SetupAxes(nullptr, nullptr, ax_flags_x, ax_flags_y);\n                        ImPlot::SetupAxisScale(ImAxis_Y1, TransformForward_Custom, TransformInverse_Custom);\n                        ImPlot::SetupAxesLimits(0, 200, min_time, max_time, ImGuiCond_Always);\n                        ImPlot::SetNextLineStyle(HUDElements.colors.frametime, 1.5);\n                        ImPlot::PlotLine(\"frametime line\", frametime_data.data(), frametime_data.size());\n                        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] &&\n                            gpus && gpus->active_gpu() && gpus->active_gpu()->throttling()){\n                            ImPlot::SetNextLineStyle(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), 1.5);\n                            ImPlot::PlotLine(\"power line\", gpus->active_gpu()->throttling()->power.data(), gpus->active_gpu()->throttling()->power.size());\n                            ImPlot::SetNextLineStyle(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.5);\n                            ImPlot::PlotLine(\"thermal line\", gpus->active_gpu()->throttling()->thermal.data(), gpus->active_gpu()->throttling()->thermal.size());\n                        }\n                        ImPlot::EndPlot();\n                    }\n                }\n#endif\n            }\n        }\n        ImGui::EndChild();\n#ifdef __linux__\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] &&\n            gpus && gpus->active_gpu() && gpus->active_gpu()->throttling()){\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n\n            if (gpus->active_gpu()->throttling()->power_throttling()) {\n                ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), \"%s\", ICON_FK_SQUARE);\n                ImGui::SameLine();\n                ImGui::Text(\"Power throttling\");\n            }\n\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n\n            if (gpus->active_gpu()->throttling()->thermal_throttling()) {\n                ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), \"%s\", ICON_FK_SQUARE);\n                ImGui::SameLine();\n                ImGui::Text(\"Thermal throttling\");\n            }\n        }\n        ImGui::PopFont();\n        ImGui::PopStyleColor();\n#endif\n    }\n}\n\nvoid HudElements::media_player(){\n#ifdef HAVE_DBUS\n    if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_media_player])\n        return;\n\n    ImguiNextColumnFirstItem();\n    uint32_t f_idx = (HUDElements.sw_stats->n_frames - 1) % ARRAY_SIZE(HUDElements.sw_stats->frames_stats);\n    uint64_t frame_timing = HUDElements.sw_stats->frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing];\n    ImFont scaled_font = *HUDElements.sw_stats->font_text;\n    scaled_font.Scale = HUDElements.params->font_scale_media_player;\n    ImGui::PushFont(&scaled_font);\n    {\n        std::unique_lock<std::mutex> lck(main_metadata.mtx, std::try_to_lock);\n        if (lck.owns_lock())\n            render_mpris_metadata(*HUDElements.params, main_metadata, frame_timing);\n        else\n            SPDLOG_DEBUG(\"failed to acquire lock\");\n    }\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n        ImguiNextColumnFirstItem();\n    }\n    if (!main_metadata.meta.playing) {\n        HUDElements.TextColored(HUDElements.colors.media_player, \"(paused)\");\n    }\n\n    ImGui::PopFont();\n#endif\n}\n\nvoid HudElements::resolution(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_resolution]){\n        ImguiNextColumnFirstItem();\n        const auto res  = ImGui::GetIO().DisplaySize;\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        const char * title = \"Resolution\";\n        HUDElements.TextColored(HUDElements.colors.engine, title);\n        ImguiNextColumnOrNewRow();\n\n        // Jump a column if title is overflowing\n        if (ImGuiTextOverflow(title))\n            ImguiNextColumnOrNewRow();\n\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.5f, \"%.0fx%.0f\", res.x, res.y);\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::show_fps_limit(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_show_fps_limit]){\n        if (fps_limiter && fps_limiter->active) {\n            ImguiNextColumnFirstItem();\n            ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n            const char* method = fps_limiter->use_early ? \"early\" : \"late\";\n            HUDElements.TextColored(HUDElements.colors.engine, \"%s\",\"FPS limit\");\n            ImguiNextColumnOrNewRow();\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", method);\n            ImguiNextColumnOrNewRow();\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", fps_limiter->current_limit());\n            ImGui::PopFont();\n        }\n    }\n}\n\nvoid HudElements::custom_text_center(){\n    if (HUDElements.place >= 0 &&\n        static_cast<size_t>(HUDElements.place) < HUDElements.ordered_functions.size()) {\n\n        if (!HUDElements.sw_stats || !HUDElements.sw_stats->font_secondary) {\n            return;\n        }\n\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n\n        const std::string& value = HUDElements.ordered_functions[HUDElements.place].value;\n\n        center_text(value);\n        HUDElements.TextColored(HUDElements.colors.text, \"%s\", value.c_str());\n\n        ImGui::NewLine();\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::custom_text(){\n    ImguiNextColumnFirstItem();\n    ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n    const char* value;\n    if (size_t(HUDElements.place) < HUDElements.ordered_functions.size())\n        value = HUDElements.ordered_functions[HUDElements.place].value.c_str();\n    else {\n        ImGui::PopFont();\n        return;\n    }\n    HUDElements.TextColored(HUDElements.colors.text, \"%s\",value);\n    ImGui::PopFont();\n}\n\nvoid HudElements::_exec(){\n    //const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;\n    ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n    ImguiNextColumnFirstItem();\n    for (auto& item : HUDElements.exec_list){\n        if (item.pos == HUDElements.place){\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n                HUDElements.TextColored(HUDElements.colors.text, \"%s\",item.ret.c_str());\n            else\n                right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, \"%s\", item.ret.c_str());\n        }\n    }\n    ImGui::PopFont();\n}\n\nvoid HudElements::gamemode(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gamemode]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"GAMEMODE\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", HUDElements.gamemode_bol ? \"ON\" : \"OFF\");\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::vkbasalt(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vkbasalt]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"VKBASALT\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", HUDElements.vkbasalt_bol ? \"ON\" : \"OFF\");\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::battery(){\n#ifdef __linux__\n    if (Battery_Stats.batt_count > 0) {\n        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery]) {\n            ImguiNextColumnFirstItem();\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact])\n                HUDElements.TextColored(HUDElements.colors.battery, \"BAT\");\n            else\n                HUDElements.TextColored(HUDElements.colors.battery, \"BATT\");\n            ImguiNextColumnOrNewRow();\n            if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_icon]) {\n                switch(int(Battery_Stats.current_percent)){\n                    case 0 ... 33:\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_QUARTER);\n                        break;\n                    case 34 ... 66:\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_HALF);\n                        break;\n                    case 67 ... 97:\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_THREE_QUARTERS);\n                        break;\n                    case 98 ... 100:\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_FULL);\n                        break;\n                }\n            }\n            else {\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", Battery_Stats.current_percent);\n                ImGui::SameLine(0,1.0f);\n                HUDElements.TextColored(HUDElements.colors.text, \"%%\");\n            }\n            if (Battery_Stats.current_watt != 0) {\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_watt]){\n                    ImguiNextColumnOrNewRow();\n                    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] && Battery_Stats.current_watt >= 10.0f)\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", Battery_Stats.current_watt);\n                    else\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.1f\", Battery_Stats.current_watt);\n                    ImGui::SameLine(0,1.0f);\n                    ImGui::PushFont(HUDElements.sw_stats->font_small);\n                    HUDElements.TextColored(HUDElements.colors.text, \"W\");\n                    ImGui::PopFont();\n                }\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_time]) {\n                    float hours;\n                    float minutes;\n                    minutes = std::modf(Battery_Stats.remaining_time, &hours);\n                    minutes *= 60;\n                    char time_buffer[32];\n                    snprintf(time_buffer, sizeof(time_buffer), \"%02d:%02d\", static_cast<int>(hours), static_cast<int>(minutes));\n\n                    if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n                        ImGui::TableNextRow();\n                        ImGui::NextColumn();\n                        ImGui::PushFont(HUDElements.sw_stats->font_small);\n                        ImGuiTableSetColumnIndex(0);\n                        HUDElements.TextColored(HUDElements.colors.text, \"%s\", \"Remaining Time\");\n                        ImGui::PopFont();\n                        ImGuiTableSetColumnIndex(2);\n                    } else {\n                        if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n                            ImguiNextColumnOrNewRow();\n\n                        ImguiNextColumnOrNewRow();\n                    }\n                    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact])\n                        ImGuiTableSetColumnIndex(0);\n\n                    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", time_buffer);\n                }\n            } else {\n                ImguiNextColumnOrNewRow();\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_PLUG);\n            }\n        }\n\n    }\n#endif\n}\n\nvoid HudElements::gamescope_fsr(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fsr] && HUDElements.g_fsrUpscale >= 0) {\n        ImguiNextColumnFirstItem();\n        string FSR_TEXT;\n        ImVec4 FSR_COLOR;\n        if (HUDElements.g_fsrUpscale){\n            FSR_TEXT = \"ON\";\n            FSR_COLOR = HUDElements.colors.fps_value_high;\n        } else {\n            FSR_TEXT = \"OFF\";\n            FSR_COLOR = HUDElements.colors.fps_value_low;\n        }\n\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"FSR\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(FSR_COLOR, HUDElements.ralign_width, \"%s\", FSR_TEXT.c_str());\n        if (HUDElements.g_fsrUpscale){\n            if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness]) {\n                ImguiNextColumnOrNewRow();\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", HUDElements.g_fsrSharpness);\n                ImGui::SameLine(0,1.0f);\n                ImGui::PushFont(HUDElements.sw_stats->font_small);\n                HUDElements.TextColored(HUDElements.colors.text, \"Sharp\");\n                ImGui::PopFont();\n            }\n        }\n    }\n}\n\nvoid HudElements::gamescope_frame_timing(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_debug]) {\n        static std::vector<float>::iterator min, max;\n        static double min_time = 0.0f;\n        static double max_time = 50.0f;\n        if (HUDElements.gamescope_debug_app.size() > 0 && HUDElements.gamescope_debug_app.back() > -1){\n            auto min = std::min_element(HUDElements.gamescope_debug_app.begin(),\n                                        HUDElements.gamescope_debug_app.end());\n            auto max = std::max_element(HUDElements.gamescope_debug_app.begin(),\n                                        HUDElements.gamescope_debug_app.end());\n\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"App\");\n            ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1);\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, \"min: %.1fms, max: %.1fms\", min[0], max[0]);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            ImguiNextColumnFirstItem();\n            ImGui::PopFont();\n            char hash[40];\n            snprintf(hash, sizeof(hash), \"##%s\", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]);\n            HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing;\n            HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */\n\n            ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n            if (ImGui::BeginChild(\"gamescope_app_window\", ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50))) {\n                ImGui::PlotLines(\"gamescope debug lines\", HUDElements.gamescope_debug_app.data(),\n                        HUDElements.gamescope_debug_app.size(), 0,\n                        NULL, min_time, max_time,\n                            ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n            }\n            ImGui::PopStyleColor();\n            ImGui::EndChild();\n        }\n        if (HUDElements.gamescope_debug_latency.size() > 0 && HUDElements.gamescope_debug_latency.back() > -1){\n            ImguiNextColumnOrNewRow();\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Latency\");\n            ImGui::TableNextRow();\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            min = std::min_element(HUDElements.gamescope_debug_latency.begin(),\n                                   HUDElements.gamescope_debug_latency.end());\n            max = std::max_element(HUDElements.gamescope_debug_latency.begin(),\n                                   HUDElements.gamescope_debug_latency.end());\n            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, \"min: %.1fms, max: %.1fms\", min[0], max[0]);\n            ImGui::PopFont();\n            ImguiNextColumnFirstItem();\n            ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n            ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(0,0,1,1));\n            if (ImGui::BeginChild(\"gamescope_latency_window\", ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50))) {\n                ImGui::PlotLines(\"gamescope debug latency lines\", HUDElements.gamescope_debug_latency.data(),\n                        HUDElements.gamescope_debug_latency.size(), 0,\n                        NULL, min_time, max_time,\n                        ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n            }\n            ImGui::PopStyleColor(2);\n            ImGui::EndChild();\n        }\n    }\n}\n\nvoid HudElements::device_battery()\n{\n#ifdef __linux__\n    std::unique_lock<std::mutex> l(device_lock);\n    if (!HUDElements.params->device_battery.empty()) {\n        if (device_found) {\n            for (int i = 0; i < device_count; i++) {\n                std::string battery = device_data[i].battery;\n                std::string name = device_data[i].name;\n                std::string battery_percent = device_data[i].battery_percent;\n                bool report_percent = device_data[i].report_percent;\n                bool charging = device_data[i].is_charging;\n\n                ImguiNextColumnFirstItem();\n                ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n                HUDElements.TextColored(HUDElements.colors.engine, \"%s\", name.c_str());\n                ImguiNextColumnOrNewRow();\n                if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon]) {\n                    if (charging)\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_USB);\n                    else {\n                        if (battery == \"Full\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_FULL);\n                        else if (battery == \"High\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_THREE_QUARTERS);\n                        else if (battery == \"Normal\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_HALF);\n                        else if (battery == \"Low\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_BATTERY_QUARTER);\n                        else if (battery == \"Unknown\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_USB);\n                    }\n                }\n                else {\n                    if (charging)\n                        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_USB);\n                    else if (report_percent) {\n                        right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, \"%s\", battery_percent.c_str());\n                        ImGui::SameLine(0,1.0f);\n                        HUDElements.TextColored(HUDElements.colors.text, \"%%\");\n                    }\n                    else {\n                        if (battery == \"Unknown\")\n                            right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", ICON_FK_USB);\n                        else\n                            right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, \"%s\", battery.c_str());\n                    }\n                }\n                if (device_count > 1 && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n                    ImGui::TableNextRow();\n                ImGui::PopFont();\n            }\n        }\n    }\n#endif\n}\n\nvoid HudElements::frame_count(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_count]){\n        ImguiNextColumnFirstItem();\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        HUDElements.TextColored(HUDElements.colors.engine, \"Frame Count\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%\" PRIu64, HUDElements.sw_stats->n_frames);\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::fan(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fan] && fan_speed != -1) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"FAN\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, \"%i\", fan_speed);\n        ImGui::SameLine(0, 1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"RPM\");\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::throttling_status(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] && gpus){\n        auto gpu = gpus->active_gpu();\n        if (!gpu)\n            return;\n\n        if ((gpu->metrics.is_power_throttled || gpu->metrics.is_current_throttled || gpu->metrics.is_temp_throttled || gpu->metrics.is_other_throttled)){\n            ImguiNextColumnFirstItem();\n            HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Throttling\");\n            ImguiNextColumnOrNewRow();\n            ImguiNextColumnOrNewRow();\n            if (gpu->metrics.is_power_throttled)\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"Power\");\n            if (gpu->metrics.is_current_throttled)\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"Current\");\n            if (gpu->metrics.is_temp_throttled)\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"Temp\");\n            if (gpu->metrics.is_other_throttled)\n                right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"Other\");\n        }\n    }\n}\n\nvoid HudElements::duration(){\n    ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n    ImguiNextColumnFirstItem();\n    HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Duration\");\n    ImguiNextColumnOrNewRow();\n    std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();\n    std::chrono::duration<double> elapsedTime = currentTime - HUDElements.overlay_start;\n    int hours = std::chrono::duration_cast<std::chrono::hours>(elapsedTime).count();\n    int minutes = std::chrono::duration_cast<std::chrono::minutes>(elapsedTime).count() % 60;\n    int seconds = std::chrono::duration_cast<std::chrono::seconds>(elapsedTime).count() % 60;\n    if (hours > 0)\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%02d:%02d:%02d\", hours, minutes, seconds);\n    else if (minutes > 0)\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%02d:%02d\", minutes, seconds);\n    else\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%02d\", seconds);\n    ImGui::PopFont();\n}\n\nvoid HudElements::graphs(){\n    ImguiNextColumnFirstItem();\n    ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n    const std::string& value = HUDElements.ordered_functions[HUDElements.place].value;\n    assert(kMaxGraphEntries >= graph_data.size());\n    std::vector<float> arr(kMaxGraphEntries - graph_data.size());\n\n    ImGui::PushFont(HUDElements.sw_stats->font_small);\n    if (value == \"cpu_load\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.cpu_load));\n        }\n        HUDElements.max = 100;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"CPU Load\");\n    }\n\n    if (value == \"gpu_load\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.gpu_load));\n        }\n        HUDElements.max = 100;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"GPU Load\");\n    }\n\n    if (value == \"cpu_temp\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.cpu_temp));\n        }\n        if (int(arr.back()) > HUDElements.cpu_temp_max)\n            HUDElements.cpu_temp_max = arr.back();\n\n        HUDElements.max = HUDElements.cpu_temp_max;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"CPU Temp\");\n    }\n\n    if (value == \"gpu_temp\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.gpu_temp));\n        }\n        if (int(arr.back()) > HUDElements.gpu_temp_max)\n            HUDElements.gpu_temp_max = arr.back();\n\n        HUDElements.max = HUDElements.gpu_temp_max;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"GPU Temp\");\n    }\n\n    if (value == \"gpu_core_clock\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.gpu_core_clock));\n        }\n        if (int(arr.back()) > HUDElements.gpu_core_max)\n            HUDElements.gpu_core_max = arr.back();\n\n        HUDElements.max = HUDElements.gpu_core_max;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"GPU Core Clock\");\n    }\n\n    if (value == \"gpu_mem_clock\"){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.gpu_mem_clock));\n        }\n        if (int(arr.back()) > HUDElements.gpu_mem_max)\n            HUDElements.gpu_mem_max = arr.back();\n\n        HUDElements.max = HUDElements.gpu_mem_max;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"GPU Mem Clock\");\n    }\n\n    if (value == \"vram\" && gpus){\n        for (auto& it : graph_data){\n            arr.push_back(float(it.gpu_vram_used));\n        }\n\n        auto gpu = gpus->active_gpu();\n        if (!gpu)\n            return;\n\n        HUDElements.max = gpu->metrics.memoryTotal;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"VRAM\");\n    }\n#ifdef __linux__\n    if (value == \"ram\"){\n\n        for (auto& it : graph_data){\n            arr.push_back(float(it.ram_used));\n        }\n\n        HUDElements.max = memmax;\n        HUDElements.min = 0;\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"RAM\");\n    }\n#endif\n    ImGui::PopFont();\n    ImGui::Dummy(ImVec2(0.0f,5.0f));\n    ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n    if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){\n        ImGui::PlotLines(\"\", arr.data(),\n                arr.size(), 0,\n                NULL, HUDElements.min, HUDElements.max,\n                ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n    } else {\n        ImGui::PlotHistogram(\"\", arr.data(),\n            arr.size(), 0,\n            NULL, HUDElements.min, HUDElements.max,\n            ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n    }\n    ImGui::Dummy(ImVec2(0.0f,5.0f));\n    ImGui::PopStyleColor(1);\n}\n\nvoid HudElements::exec_name(){\n    if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_exec_name]){\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Exe name\");\n        ImguiNextColumnOrNewRow();\n        ImVec2 text_size = ImGui::CalcTextSize(global_proc_name.c_str());\n        right_aligned_text(HUDElements.colors.text, text_size.x, global_proc_name.c_str());\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::fps_metrics(){\n    if (!fpsmetrics)\n        return;\n\n    for (auto& metric : fpsmetrics->copy_metrics()){\n        if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n            ImGui::TableNextRow();\n\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", metric.display_name.c_str());\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", metric.value);\n        ImGui::SameLine(0, 1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"FPS\");\n        ImGui::PopFont();\n        ImguiNextColumnOrNewRow();\n    }\n}\n\nvoid HudElements::hdr() {\n    if (HUDElements.hdr_status > 0) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"HDR\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.fps_value_high, HUDElements.ralign_width, \"ON\");\n    }\n}\n\nvoid HudElements::refresh_rate() {\n    if (HUDElements.refresh > 0) {\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Display Hz\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%i\", HUDElements.refresh);\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::winesync() {\n    static std::unique_ptr<WineSync> winesync_ptr = nullptr;\n    if (!winesync_ptr)\n        winesync_ptr = std::make_unique<WineSync>();\n\n    if (winesync_ptr->valid()) {\n        winesync_ptr->set_pid(HUDElements.g_gamescopePid);\n        ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"WSYNC\");\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", winesync_ptr->get_method());\n        ImGui::PopFont();\n    }\n}\n\nvoid HudElements::present_mode() {\n    ImguiNextColumnFirstItem();\n    ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n    const char* title;\n\n    if (HUDElements.is_vulkan)\n        title = \"Present Mode\";\n    else\n        title = \"VSYNC\";\n\n    HUDElements.TextColored(HUDElements.colors.engine, \"%s\", title);\n    ImguiNextColumnOrNewRow();\n\n    // Jump a column if title is overflowing\n    if (ImGuiTextOverflow(title))\n        ImguiNextColumnOrNewRow();\n\n\n    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 2.0f, \"%s\\n\", HUDElements.get_present_mode().c_str());\n\n    ImGui::PopFont();\n}\n\nvoid HudElements::network() {\n#ifdef __linux__\n    if (HUDElements.net && HUDElements.net->should_reset)\n        HUDElements.net.reset(new Net);\n\n    if (!HUDElements.net)\n        HUDElements.net = std::make_unique<Net>();\n\n    for (auto& iface : HUDElements.net->interfaces){\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.network, \"%.8s\", iface.name.c_str());\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", iface.txBps / 1000.f);\n        ImGui::SameLine(0,1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"KB/s %s\", ICON_FK_ARROW_UP);\n        ImGui::PopFont();\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%.0f\", iface.rxBps / 1000.f);\n        ImGui::SameLine(0,1.0f);\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.text, \"KB/s %s\", ICON_FK_ARROW_DOWN);\n        ImGui::PopFont();\n    }\n#endif\n}\n\nvoid HudElements::_display_session() {\n    if (not HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_display_server])\n        return;\n\n    ImGui::PushFont(HUDElements.sw_stats->font_secondary);\n    ImguiNextColumnFirstItem();\n\n    const char* title = \"Display Server\";\n    HUDElements.TextColored(HUDElements.colors.engine, \"%s\", title);\n    ImguiNextColumnOrNewRow();\n\n    // Jump a column if title is overflowing\n    if (ImGuiTextOverflow(title))\n        ImguiNextColumnOrNewRow();\n\n    static std::map<display_servers, std::string> servers {\n        {WAYLAND, {\"WAYLAND\"}},\n        {XWAYLAND, {\"XWAYLAND\"}},\n        {XORG, {\"XORG\"}}\n    };\n    right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.5f, \"%s\", servers[HUDElements.display_server].c_str());\n    ImGui::PopFont();\n}\n\nvoid HudElements::fex_stats()\n{\n#ifdef HAVE_FEX\n    if (!HUDElements.params->fex_stats.enabled) {\n        return;\n    }\n\n    ImGui::PushFont(HUDElements.sw_stats->font_small);\n\n    if (HUDElements.params->fex_stats.status) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"FEX\");\n        ImguiNextColumnOrNewRow();\n        ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", fex::fex_status);\n    }\n\n    if (!fex::is_fex_pid_found()) {\n        ImGui::PopFont();\n        return;\n    }\n\n    if (HUDElements.params->fex_stats.app_type) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Type\");\n        ImguiNextColumnOrNewRow();\n        ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%s\", fex::get_fex_app_type());\n    }\n\n    if (HUDElements.params->fex_stats.sigbus_counts) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"SIGBUS\");\n        ImguiNextColumnOrNewRow();\n        ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%\" PRIu64 \" - %.0f avg/s\", fex::sigbus_counts.Count(), fex::sigbus_counts.Avg());\n    }\n\n    if (HUDElements.params->fex_stats.smc_counts) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"SMC\");\n        ImguiNextColumnOrNewRow();\n        ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%\" PRIu64 \" - %.0f avg/s\", fex::smc_counts.Count(), fex::smc_counts.Avg());\n    }\n\n    if (HUDElements.params->fex_stats.softfloat_counts) {\n        ImguiNextColumnFirstItem();\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"Softfloat\");\n        ImguiNextColumnOrNewRow();\n        ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n        ImguiNextColumnOrNewRow();\n        right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, \"%\" PRIu64 \" - %.0f avg/s\", fex::softfloat_counts.Count(), fex::softfloat_counts.Avg());\n    }\n\n    ImGui::PopFont();\n\n    ImguiNextColumnFirstItem();\n    ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n\n    if (HUDElements.params->fex_stats.hot_threads) {\n        // Draw hot threads\n        bool Warning = false;\n        ImVec4 WarningColor;\n\n        for (auto it : fex::fex_max_thread_loads){\n            if (it >= 75.0) {\n                Warning = true;\n                WarningColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);\n            }\n            else if (it >= 50.0) {\n                Warning = true;\n                WarningColor = ImVec4(1.0f, 1.0f, 0.0f, 1.0f);\n            }\n        }\n\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"FEX JIT top loaded threads\");\n        ImGui::PopFont();\n\n        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n        if (Warning) {\n            ImGui::PushStyleColor(ImGuiCol_PlotHistogram, WarningColor);\n        }\n\n        ImGui::PlotHistogram(\"\", fex::fex_max_thread_loads.data(),\n            fex::fex_max_thread_loads.size(), 0,\n            NULL, 0, 100,\n            ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n        ImGui::PopStyleColor(1 + (Warning ? 1 : 0));\n    }\n\n    if (HUDElements.params->fex_stats.jit_load) {\n        ImGui::PushFont(HUDElements.sw_stats->font_small);\n        HUDElements.TextColored(HUDElements.colors.engine, \"%s\", \"FEX JIT Load\");\n        ImGui::PopFont();\n\n        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));\n\n        ImGui::PlotLines(\"\", fex::fex_load_data.data(),\n            fex::fex_load_data.size(), 0,\n            NULL, 0, 100,\n            ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50));\n        ImGui::PopStyleColor(1);\n    }\n#endif //HAVE_FEX\n}\n\nvoid HudElements::ftrace() {\n#ifdef HAVE_FTRACE\n    if (!HUDElements.params->ftrace.enabled || !FTrace::object)\n        return;\n\n    float width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x);\n    float height = 100;\n\n    for (auto& tp : FTrace::object->tracepoints()) {\n        switch (tp->type) {\n        case FTrace::TracepointType::Histogram:\n        case FTrace::TracepointType::LineGraph:\n        {\n            char hash[40];\n            snprintf(hash, sizeof(hash), \"##%s\", tp->name.c_str());\n\n            ImGui::TableNextRow();\n            ImguiNextColumnFirstItem();\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            HUDElements.TextColored(HUDElements.colors.text, \"ftrace %s: %s\",\n                                    tp->type == FTrace::TracepointType::Histogram ? \"histogram\" : \"line graph\",\n                                    tp->name.c_str());\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            if (tp->type == FTrace::TracepointType::LineGraph) {\n               HUDElements.TextColored(HUDElements.colors.text, \"    parameter: %s\", tp->field_name.c_str());\n               ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            }\n            ImGui::PopFont();\n            if (ImGui::BeginChild(tp->name.c_str(), ImVec2(width, height), false, ImGuiWindowFlags_NoDecoration)) {\n                if (tp->type == FTrace::TracepointType::Histogram) {\n                    ImGui::PlotHistogram(hash, FTrace::FTrace::get_plot_values, tp.get(), FTrace::Tracepoint::PLOT_DATA_CAPACITY, 0,\n                                         NULL, tp->data.plot.range.min, tp->data.plot.range.max, ImVec2(width, height));\n                } else {\n                    ImGui::PlotLines(hash, FTrace::FTrace::get_plot_values, tp.get(), FTrace::Tracepoint::PLOT_DATA_CAPACITY, 0,\n                                         NULL, tp->data.plot.range.min, tp->data.plot.range.max, ImVec2(width, height));\n                }\n            }\n            ImGui::EndChild();\n            break;\n        }\n        case FTrace::TracepointType::Label:\n        {\n            ImGui::TableNextRow();\n            ImguiNextColumnFirstItem();\n            ImGui::PushFont(HUDElements.sw_stats->font_small);\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y));\n            HUDElements.TextColored(HUDElements.colors.text, \"ftrace label: %s:\", tp->name.c_str());\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            HUDElements.TextColored(HUDElements.colors.text, \"    %s=%s\", tp->field_name.c_str(), tp->data.field_value.c_str());\n            ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2));\n            ImGui::PopFont();\n            break;\n        }\n        default:\n            UNREACHABLE(\"invalid tracepoint type\");\n        }\n    }\n#endif // HAVE_FTRACE\n}\n\nvoid HudElements::sort_elements(const std::pair<std::string, std::string>& option) {\n    const auto& param = option.first;\n    const auto& value = option.second;\n\n    // Initialize a map of display parameters and their corresponding functions.\n    const std::map<std::string, Function> display_params = {\n        {\"version\", {version}},\n        {\"time\", {time}},\n        {\"gpu_stats\", {gpu_stats}},\n        {\"cpu_stats\", {cpu_stats}},\n        {\"core_load\", {core_load}},\n        {\"io_read\", {io_stats}},\n        {\"io_write\", {io_stats}},\n        {\"arch\", {arch}},\n        {\"wine\", {wine}},\n        {\"procmem\", {procmem}},\n        {\"gamemode\", {gamemode}},\n        {\"vkbasalt\", {vkbasalt}},\n        {\"engine_version\", {engine_version}},\n        {\"vulkan_driver\", {vulkan_driver}},\n        {\"resolution\", {resolution}},\n        {\"show_fps_limit\", {show_fps_limit}},\n        {\"vram\", {vram}},\n        {\"proc_vram\", {proc_vram}},\n        {\"ram\", {ram}},\n        {\"fps\", {fps}},\n        {\"gpu_name\", {gpu_name}},\n        {\"frame_timing\", {frame_timing}},\n        {\"media_player\", {media_player}},\n        {\"custom_text\", {custom_text}},\n        {\"custom_text_center\", {custom_text_center}},\n        {\"exec\", {_exec}},\n        {\"battery\", {battery}},\n        {\"fps_only\", {fps_only}},\n        {\"fsr\", {gamescope_fsr}},\n        {\"debug\", {gamescope_frame_timing}},\n        {\"device_battery\", {device_battery}},\n        {\"frame_count\", {frame_count}},\n        {\"fan\", {fan}},\n        {\"throttling_status\", {throttling_status}},\n        {\"exec_name\", {exec_name}},\n        {\"duration\", {duration}},\n        {\"graphs\", {graphs}},\n        {\"fps_metrics\", {fps_metrics}},\n        {\"hdr\", {hdr}},\n        {\"refresh_rate\", {refresh_rate}},\n        {\"winesync\", {winesync}},\n        {\"present_mode\", {present_mode}},\n        {\"network\", {network}},\n        {\"display_server\", {_display_session}},\n        {\"fex_stats\", {fex_stats}},\n        {\"ftrace\", {ftrace}},\n    };\n\n    auto check_param = display_params.find(param);\n    if (check_param != display_params.end()) {\n        const Function& func = check_param->second;\n\n        if (param == \"debug\") {\n            ordered_functions.push_back({gamescope_frame_timing, \"gamescope_frame_timing\", value});\n        } else if (param == \"fsr\") {\n            ordered_functions.push_back({gamescope_fsr, \"gamescope_fsr\", value});\n        } else if (param == \"io_read\" || param == \"io_write\") {\n            // Don't add twice\n            if (std::none_of(ordered_functions.begin(), ordered_functions.end(),\n                [](const auto& a) { return a.name == \"io_stats\"; })) {\n                ordered_functions.push_back({io_stats, \"io_stats\", value});\n            }\n        } else if (param == \"exec\") {\n            ordered_functions.push_back({_exec, \"exec\", value});\n            exec_list.push_back({int(ordered_functions.size() - 1), value});\n        } else if (param == \"graphs\") {\n            auto values = str_tokenize(value);\n            for (auto& val : values) {\n                if (find(permitted_params.begin(), permitted_params.end(), val) != permitted_params.end()) {\n                    ordered_functions.push_back({graphs, \"graph: \" + val, val});\n                } else {\n                    SPDLOG_ERROR(\"Unrecognized graph type: {}\", val);\n                }\n            }\n        } else {\n            // Use this to always add to the front of the vector\n            // ordered_functions.insert(ordered_functions.begin(), std::make_pair(param, value));\n            ordered_functions.push_back({func.run, param, value});\n        }\n    }\n    return;\n}\n\nvoid HudElements::legacy_elements(const overlay_params* temp_params){\n    string value = \"NULL\";\n    ordered_functions.clear();\n\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_time])\n        ordered_functions.push_back({time, \"time\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_version])\n        ordered_functions.push_back({version, \"version\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats])\n        ordered_functions.push_back({gpu_stats, \"gpu_stats\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats])\n        ordered_functions.push_back({cpu_stats, \"cpu_stats\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_core_load])\n        ordered_functions.push_back({core_load, \"core_load\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_io_read] || temp_params->enabled[OVERLAY_PARAM_ENABLED_io_write])\n        ordered_functions.push_back({io_stats, \"io_stats\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vram])\n        ordered_functions.push_back({vram, \"vram\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_proc_vram])\n        ordered_functions.push_back({proc_vram, \"proc_vram\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_ram])\n        ordered_functions.push_back({ram, \"ram\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_procmem])\n        ordered_functions.push_back({procmem, \"procmem\", value});\n    if (!temp_params->network.empty())\n        ordered_functions.push_back({network, \"network\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_battery])\n        ordered_functions.push_back({battery, \"battery\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fan])\n        ordered_functions.push_back({fan, \"fan\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fsr])\n        ordered_functions.push_back({gamescope_fsr, \"gamescope_fsr\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_hdr])\n        ordered_functions.push_back({hdr, \"hdr\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_throttling_status])\n        ordered_functions.push_back({throttling_status, \"throttling_status\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fps])\n        ordered_functions.push_back({fps, \"fps\", value});\n    for (const auto& pair : options) {\n        if (pair.first.find(\"graphs\") != std::string::npos) {\n            std::stringstream ss(pair.second);\n            std::string token;\n            while (std::getline(ss, token, ',')){\n                ordered_functions.push_back({graphs, \"graphs\", token});\n            }\n        }\n    }\n    if (!temp_params->fps_metrics.empty())\n        ordered_functions.push_back({fps_metrics, \"fps_metrics\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fps_only])\n        ordered_functions.push_back({fps_only, \"fps_only\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_engine_version])\n        ordered_functions.push_back({engine_version, \"engine_version\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gpu_name])\n        ordered_functions.push_back({gpu_name, \"gpu_name\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vulkan_driver])\n        ordered_functions.push_back({vulkan_driver, \"vulkan_driver\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_arch])\n        ordered_functions.push_back({arch, \"arch\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_wine])\n        ordered_functions.push_back({wine, \"wine\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_frame_timing])\n        ordered_functions.push_back({frame_timing, \"frame_timing\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_frame_count])\n        ordered_functions.push_back({frame_count, \"frame_count\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_debug] && !temp_params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n        ordered_functions.push_back({gamescope_frame_timing, \"gamescope_frame_timing\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gamemode])\n        ordered_functions.push_back({gamemode, \"gamemode\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vkbasalt])\n        ordered_functions.push_back({vkbasalt, \"vkbasalt\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_show_fps_limit])\n        ordered_functions.push_back({show_fps_limit, \"show_fps_limit\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_resolution])\n        ordered_functions.push_back({resolution, \"resolution\", value});\n    if (!temp_params->device_battery.empty() )\n        ordered_functions.push_back({device_battery, \"device_battery\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_media_player])\n        ordered_functions.push_back({media_player, \"media_player\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_exec_name])\n        ordered_functions.push_back({exec_name, \"exec_name\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_duration])\n        ordered_functions.push_back({duration, \"duration\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_winesync])\n        ordered_functions.push_back({winesync, \"winesync\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_present_mode])\n        ordered_functions.push_back({present_mode, \"present_mode\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_refresh_rate])\n        ordered_functions.push_back({refresh_rate, \"refresh_rate\", value});\n    if (temp_params->enabled[OVERLAY_PARAM_ENABLED_display_server])\n        ordered_functions.push_back({_display_session, \"display_session\", value});\n    if (temp_params->fex_stats.enabled)\n        ordered_functions.push_back({fex_stats, \"fex_stats\", value});\n#ifdef HAVE_FTRACE\n    if (temp_params->ftrace.enabled)\n        ordered_functions.push_back({ftrace, \"ftrace\", value});\n#endif\n}\n\nvoid HudElements::update_exec(){\n#ifdef __linux__\n    // TODO: exec needs a rewrite using as using fork() is not safe in multithread.\n    // We should probably use posix_spawn instead.\n    // This currently stalls games using feral launcher.\n    // For now don't init shell unless we have some exec options.\n    if (exec_list.empty())\n        return;\n\n    if (!HUDElements.shell)\n        HUDElements.shell = std::make_unique<Shell>();\n\n    for(auto& item : exec_list){\n        std::string ret = HUDElements.shell->exec(item.value + \"\\n\");\n        // use the previous ret if we get bad system call\n        if (ret.find(\"Bad system call\") == std::string::npos)\n            item.ret = ret;\n    }\n#endif\n}\n\nstd::string_view HudElements::get_vulkan_present_mode_short_name(VkPresentModeKHR mode) {\n    static constexpr std::string_view prefix = \"VK_PRESENT_MODE_\";\n    static constexpr std::string_view suffix = \"_KHR\";\n\n    auto name = std::string_view{string_VkPresentModeKHR(mode)};\n    name = strip_prefix(name, prefix);\n    name = strip_suffix(name, suffix);\n\n    return name;\n}\n\nHudElements HUDElements;\n"
  },
  {
    "path": "src/hud_elements.h",
    "content": "#pragma once\n#include <vector>\n#include <string>\n#include <utility>\n#include <map>\n#include <imgui.h>\n#include \"timing.hpp\"\n#include <functional>\n#include <vulkan/vulkan.h>\n#include <vulkan/vk_enum_string_helper.h>\n#include <array>\n#include \"net.h\"\n#include \"overlay_params.h\"\n#include \"shell.h\"\n#include \"gpu.h\"\n\nstruct Function {\n    std::function<void()> run;  // Using std::function instead of a raw function pointer for more flexibility\n    std::string name;\n    std::string value;\n};\n\nclass HudElements{\n    public:\n        struct swapchain_stats *sw_stats;\n        std::shared_ptr<overlay_params> params;\n        struct exec_entry {\n            int             pos;\n            std::string     value;\n            std::string     ret;\n        };\n        float ralign_width;\n        float old_scale;\n        float res_width, res_height;\n        bool is_vulkan = true, gamemode_bol = false, vkbasalt_bol = false;\n        int place;\n        int text_column = 1;\n        int table_columns_count = 0;\n        pid_t g_gamescopePid = -1;\n        int g_fsrUpscale = -1;\n        int g_fsrSharpness = -1;\n        Clock::time_point last_exec;\n        std::vector<std::pair<std::string, std::string>> options;\n        std::vector<Function> ordered_functions;\n        std::vector<float> gamescope_debug_latency {};\n        std::vector<float> gamescope_debug_app {};\n        int min, max, gpu_core_max, gpu_mem_max, cpu_temp_max, gpu_temp_max;\n        const std::vector<std::string> permitted_params = {\n            \"gpu_load\", \"cpu_load\", \"gpu_core_clock\", \"gpu_mem_clock\",\n            \"vram\", \"ram\", \"cpu_temp\", \"gpu_temp\"\n        };\n        std::vector<exec_entry> exec_list;\n        std::chrono::steady_clock::time_point overlay_start = std::chrono::steady_clock::now();\n        uint32_t vendorID;\n        int hdr_status = 0;\n        int refresh = 0;\n        unsigned int vsync = 10;\n\n        enum display_servers {\n            UNKNOWN,\n            WAYLAND,\n            XWAYLAND,\n            XORG\n        };\n\n        display_servers display_server = UNKNOWN;\n        std::unique_ptr<Net> net = nullptr;\n#ifdef __linux__\n        std::unique_ptr<Shell> shell = nullptr;\n#endif\n\n        void sort_elements(const std::pair<std::string, std::string>& option);\n        void legacy_elements(const overlay_params* temp_params);\n        void update_exec();\n        int convert_to_fahrenheit(int celsius);\n        static void version();\n        static void time();\n        static void gpu_stats();\n        static void cpu_stats();\n        static void core_load();\n        static void io_stats();\n        static void vram();\n        static void proc_vram();\n        static void ram();\n        static void procmem();\n        static void fps();\n        static void engine_version();\n        static void gpu_name();\n        static void vulkan_driver();\n        static void arch();\n        static void wine();\n        static void frame_timing();\n        static void media_player();\n        static void resolution();\n        static void show_fps_limit();\n        static void custom_text_center();\n        static void custom_text();\n        static void vkbasalt();\n        static void gamemode();\n        static void graphs();\n        static void _exec();\n        static void battery();\n        static void fps_only();\n        static void gamescope_fsr();\n        static void gamescope_frame_timing();\n        static void device_battery();\n        static void frame_count();\n        static void fan();\n        static void throttling_status();\n        static void exec_name();\n        static void duration();\n        static void fps_metrics();\n        static void hdr();\n        static void refresh_rate();\n        static void winesync();\n        static void present_mode();\n        static void network();\n        static void _display_session();\n        static void fex_stats();\n        static void ftrace();\n\n        void convert_colors(const struct overlay_params& params);\n        void convert_colors(bool do_conv, const struct overlay_params& params);\n        struct hud_colors {\n            bool convert, update;\n            ImVec4 cpu,\n                gpu,\n                vram,\n                ram,\n                swap,\n                engine,\n                io,\n                frametime,\n                background,\n                text,\n                media_player,\n                wine,\n                horizontal_separator,\n                battery,\n                gpu_load_low,\n                gpu_load_med,\n                gpu_load_high,\n                cpu_load_low,\n                cpu_load_med,\n                cpu_load_high,\n                fps_value_low,\n                fps_value_med,\n                fps_value_high,\n                text_outline,\n                network;\n        } colors {};\n\n        void TextColored(ImVec4 col, const char *fmt, ...);\n\n        std::array<VkPresentModeKHR, 6> presentModes = {\n            VK_PRESENT_MODE_FIFO_RELAXED_KHR,\n            VK_PRESENT_MODE_IMMEDIATE_KHR,\n            VK_PRESENT_MODE_MAILBOX_KHR,\n            VK_PRESENT_MODE_FIFO_KHR,\n            VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,\n            VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR};\n\n        VkPresentModeKHR cur_present_mode;\n\n        std::string get_present_mode() {\n            if (is_vulkan)\n                return std::string(HudElements::get_vulkan_present_mode_short_name(cur_present_mode));\n            else\n                return vsync == 0 ? \"OFF\" : \"ON\";\n\n        }\n\n        static std::string_view get_vulkan_present_mode_short_name(VkPresentModeKHR mode);\n};\n\nextern HudElements HUDElements;\n"
  },
  {
    "path": "src/imgui_utils.h",
    "content": "#pragma once\n\n#include <imgui.h>\n\n#ifdef __linux__\n#include <implot.h>\n#endif\n\nstruct imgui_contexts {\n    ImGuiContext* imgui = nullptr;\n#ifdef IMPLOT_API\n    ImPlotContext* implot = nullptr;\n#endif\n};\n\nstatic imgui_contexts create_imgui_contexts(ImFontAtlas* shared_font_atlas = NULL)\n{\n    imgui_contexts contexts;\n    contexts.imgui = ImGui::CreateContext(shared_font_atlas);\n#ifdef IMPLOT_API\n    contexts.implot = ImPlot::CreateContext();\n#endif\n    return contexts;\n}\n\nstatic void destroy_imgui_contexts(imgui_contexts& contexts)\n{\n    ImGui::DestroyContext(contexts.imgui);\n    contexts.imgui = nullptr;\n#ifdef IMPLOT_API\n    ImPlot::DestroyContext(contexts.implot);\n    contexts.implot = nullptr;\n#endif\n}\n\nstatic imgui_contexts get_current_imgui_contexts() {\n    imgui_contexts saved_contexts;\n    saved_contexts.imgui = ImGui::GetCurrentContext();\n#ifdef IMPLOT_API\n    saved_contexts.implot = ImPlot::GetCurrentContext();\n#endif\n    return saved_contexts;\n}\n\nstatic void make_imgui_contexts_current(imgui_contexts contexts)\n{\n    ImGui::SetCurrentContext(contexts.imgui);\n#ifdef IMPLOT_API\n    ImPlot::SetCurrentContext(contexts.implot);\n#endif\n}\n"
  },
  {
    "path": "src/iostats.cpp",
    "content": "#include \"iostats.h\"\n#include \"string_utils.h\"\n#include <fstream>\n#include \"hud_elements.h\"\n\nstruct iostats g_io_stats;\n\nvoid getIoStats(iostats& io) {\n    Clock::time_point now = Clock::now(); /* ns */\n    std::chrono::duration<float> time_diff = now - io.last_update;\n\n    io.prev.read_bytes  = io.curr.read_bytes;\n    io.prev.write_bytes = io.curr.write_bytes;\n\n    std::string f = \"/proc/\";\n\n    {\n        auto gs_pid = HUDElements.g_gamescopePid;\n        f += gs_pid < 1 ? \"self\" : std::to_string(gs_pid);\n        f += \"/io\";\n    }\n\n    std::ifstream file(f);\n\n    if (!file.is_open()) {\n        SPDLOG_ERROR(\"can't open {}\", f);\n        return;\n    }\n\n    for (std::string line; std::getline(file, line);) {\n        if (starts_with(line, \"read_bytes:\")) {\n            try_stoull(io.curr.read_bytes, line.substr(12));\n        }\n        else if (starts_with(line, \"write_bytes:\")) {\n            try_stoull(io.curr.write_bytes, line.substr(13));\n        }\n    }\n\n    if (io.last_update.time_since_epoch().count()) {\n        io.diff.read  = (io.curr.read_bytes  - io.prev.read_bytes) / (1024.f * 1024.f);\n        io.diff.write = (io.curr.write_bytes - io.prev.write_bytes) / (1024.f * 1024.f);\n\n        io.per_second.read = io.diff.read / time_diff.count();\n        io.per_second.write = io.diff.write / time_diff.count();\n    }\n\n    io.last_update = now;\n}\n"
  },
  {
    "path": "src/iostats.h",
    "content": "#pragma once\n#ifndef MANGOHUD_IOSTATS_H\n#define MANGOHUD_IOSTATS_H\n\n#include <inttypes.h>\n#include \"timing.hpp\"\n\nstruct iostats {\n    struct {\n      unsigned long long read_bytes;\n      unsigned long long write_bytes;\n    } curr;\n    struct {\n      unsigned long long read_bytes;\n      unsigned long long write_bytes;\n    } prev;\n    struct {\n      float read;\n      float write;\n    } diff;\n    struct {\n      float read;\n      float write;\n    } per_second;\n    Clock::time_point last_update;\n};\n\nextern iostats g_io_stats;\nvoid getIoStats(iostats& io);\n\n#endif //MANGOHUD_IOSTATS_H\n"
  },
  {
    "path": "src/keybinds.cpp",
    "content": "#include <cstdint>\n#include <cstring>\n#include <array>\n#include <algorithm>\n#include <unistd.h>\n#include \"hud_elements.h\"\n#include \"overlay.h\"\n#include \"timing.hpp\"\n#include \"logging.h\"\n#include \"keybinds.h\"\n#include \"fps_metrics.h\"\n#include \"fps_limiter.h\"\n\nClock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press;\n\nvoid check_keybinds(struct overlay_params& params){\n   auto real_params = get_params();\n   using namespace std::chrono_literals;\n   auto now = Clock::now(); /* us */\n   auto elapsedF2 = now - last_f2_press;\n   auto elapsedFpsLimitToggle = now - toggle_fps_limit_press;\n   auto elapsedPresetToggle = now - toggle_preset_press;\n   auto elapsedF12 = now - last_f12_press;\n   auto elapsedReloadCfg = now - reload_cfg_press;\n   auto elapsedUpload = now - last_upload_press;\n\n   static Clock::time_point last_check;\n   if (now - last_check < 100ms)\n      return;\n   last_check = now;\n\n   const auto keyPressDelay = 400ms;\n\n   if (elapsedF2 >= keyPressDelay &&\n       keys_are_pressed(real_params->toggle_logging)) {\n      last_f2_press = now;\n      if (logger->is_active()) {\n         logger->stop_logging();\n      } else {\n         logger->start_logging();\n         benchmark.fps_data.clear();\n      }\n   }\n\n   if (elapsedFpsLimitToggle >= keyPressDelay &&\n       keys_are_pressed(real_params->toggle_fps_limit)) {\n      toggle_fps_limit_press = now;\n      fps_limiter->next_limit();\n   }\n\n   if (elapsedPresetToggle >= keyPressDelay &&\n       keys_are_pressed(real_params->toggle_preset)) {\n     toggle_preset_press = now;\n     size_t size = real_params->preset.size();\n     for (size_t i = 0; i < size; i++){\n       if(real_params->preset[i] == current_preset) {\n         current_preset = real_params->preset[++i%size];\n         parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), true);\n         break;\n       }\n     }\n   }\n\n   if (elapsedF12 >= keyPressDelay &&\n       keys_are_pressed(real_params->toggle_hud)) {\n      last_f12_press = now;\n      real_params->no_display = !real_params->no_display;\n   }\n\n   if (elapsedReloadCfg >= keyPressDelay &&\n       keys_are_pressed(real_params->reload_cfg)) {\n      parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n      reload_cfg_press = now;\n   }\n\n   if (real_params->permit_upload && elapsedUpload >= keyPressDelay &&\n       keys_are_pressed(real_params->upload_log)) {\n      last_upload_press = now;\n      logger->upload_last_log();\n   }\n\n   if (real_params->permit_upload && elapsedUpload >= keyPressDelay &&\n       keys_are_pressed(real_params->upload_logs)) {\n      last_upload_press = now;\n      logger->upload_last_logs();\n   }\n\n   if (elapsedF12 >= keyPressDelay &&\n       keys_are_pressed(real_params->toggle_hud_position)) {\n      next_hud_position();\n      last_f12_press = now;\n   }\n\n   if (elapsedF12 >= keyPressDelay &&\n       keys_are_pressed(real_params->reset_fps_metrics)) {\n      last_f12_press = now;\n      if (fpsmetrics)\n         fpsmetrics->reset_metrics();\n   }\n}\n"
  },
  {
    "path": "src/keybinds.h",
    "content": "#pragma once\n#ifndef MANGOHUD_KEYBINDS_H\n#define MANGOHUD_KEYBINDS_H\n\n#ifdef HAVE_X11\n#include \"shared_x11.h\"\n#include \"loaders/loader_x11.h\"\n#endif\n#ifdef HAVE_WAYLAND\n#include \"wayland_hook.h\"\n#endif\n\n#ifndef KeySym\ntypedef unsigned long KeySym;\n#endif\n\n#if defined(HAVE_X11) || defined(HAVE_WAYLAND)\nstatic inline bool keys_are_pressed(const std::vector<KeySym>& keys)\n{\n    if (keys.size() == 0)\n        return false;\n\n    #if defined(HAVE_WAYLAND)\n    if (wl_handle)\n    {\n        update_wl_queue();\n\n        if (wayland_has_keys_pressed(keys))\n           return true;\n    }\n    #endif\n\n    #if defined(HAVE_X11)\n    if (init_x11())\n    {\n        char keys_return[32];\n        size_t pressed = 0;\n\n        auto libx11 = get_libx11();\n        libx11->XQueryKeymap(get_xdisplay(), keys_return);\n\n        for (KeySym ks : keys) {\n            KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks);\n\n            bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7)));\n\n            if (isPressed)\n                pressed++;\n        }\n\n        if (pressed == keys.size()) {\n            return true;\n        }\n    }\n    #endif\n\n    return false;\n}\n#elif defined(_WIN32)\n#include <windows.h>\nstatic inline bool keys_are_pressed(const std::vector<KeySym>& keys) {\n    size_t pressed = 0;\n\n    for (KeySym ks : keys) {\n        if (GetAsyncKeyState(ks) & 0x8000)\n            pressed++;\n    }\n\n    if (pressed > 0 && pressed == keys.size()) {\n        return true;\n    }\n\n    return false;\n}\n#endif\n\n#endif //MANGOHUD_KEYBINDS_H\n"
  },
  {
    "path": "src/loaders/loader_dbus.cpp",
    "content": "\n#include \"loaders/loader_dbus.h\"\n#include <iostream>\n#include <spdlog/spdlog.h>\n\n// Put these sanity checks here so that they fire at most once\n// (to avoid cluttering the build output).\n#if !defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && !defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)\n#error neither LIBRARY_LOADER_DBUS_H_DLOPEN nor LIBRARY_LOADER_DBUS_H_DT_NEEDED defined\n#endif\n#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)\n#error both LIBRARY_LOADER_DBUS_H_DLOPEN and LIBRARY_LOADER_DBUS_H_DT_NEEDED defined\n#endif\n\nlibdbus_loader::libdbus_loader() : loaded_(false) {\n}\n\nlibdbus_loader::~libdbus_loader() {\n  CleanUp(loaded_);\n}\n\nbool libdbus_loader::Load(const std::string& library_name) {\n  if (loaded_) {\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)\n  library_ = dlopen(library_name.c_str(), RTLD_LAZY);\n  if (!library_) {\n    SPDLOG_ERROR(\"Failed to open \" MANGOHUD_ARCH \" {}: {}\", library_name, dlerror());\n    return false;\n  }\n\n\n  bus_add_match =\n      reinterpret_cast<decltype(this->bus_add_match)>(\n          dlsym(library_, \"dbus_bus_add_match\"));\n  if (!bus_add_match) {\n    CleanUp(true);\n    return false;\n  }\n\n  bus_get =\n      reinterpret_cast<decltype(this->bus_get)>(\n          dlsym(library_, \"dbus_bus_get\"));\n  if (!bus_get) {\n    CleanUp(true);\n    return false;\n  }\n\n  bus_get_unique_name =\n      reinterpret_cast<decltype(this->bus_get_unique_name)>(\n          dlsym(library_, \"dbus_bus_get_unique_name\"));\n  if (!bus_get_unique_name) {\n    CleanUp(true);\n    return false;\n  }\n\n  bus_remove_match =\n      reinterpret_cast<decltype(this->bus_remove_match)>(\n          dlsym(library_, \"dbus_bus_remove_match\"));\n  if (!bus_remove_match) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_add_filter =\n      reinterpret_cast<decltype(this->connection_add_filter)>(\n          dlsym(library_, \"dbus_connection_add_filter\"));\n  if (!connection_add_filter) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_pop_message =\n      reinterpret_cast<decltype(this->connection_pop_message)>(\n          dlsym(library_, \"dbus_connection_pop_message\"));\n  if (!connection_pop_message) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_read_write =\n      reinterpret_cast<decltype(this->connection_read_write)>(\n          dlsym(library_, \"dbus_connection_read_write\"));\n  if (!connection_read_write) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_read_write_dispatch =\n      reinterpret_cast<decltype(this->connection_read_write)>(\n          dlsym(library_, \"dbus_connection_read_write_dispatch\"));\n  if (!connection_read_write_dispatch) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_remove_filter =\n      reinterpret_cast<decltype(this->connection_remove_filter)>(\n          dlsym(library_, \"dbus_connection_remove_filter\"));\n  if (!connection_remove_filter) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_send_with_reply_and_block =\n      reinterpret_cast<decltype(this->connection_send_with_reply_and_block)>(\n          dlsym(library_, \"dbus_connection_send_with_reply_and_block\"));\n  if (!connection_send_with_reply_and_block) {\n    CleanUp(true);\n    return false;\n  }\n\n  connection_unref =\n      reinterpret_cast<decltype(this->connection_unref)>(\n          dlsym(library_, \"dbus_connection_unref\"));\n  if (!connection_unref) {\n    CleanUp(true);\n    return false;\n  }\n\n  error_free =\n      reinterpret_cast<decltype(this->error_free)>(\n          dlsym(library_, \"dbus_error_free\"));\n  if (!error_free) {\n    CleanUp(true);\n    return false;\n  }\n\n  error_init =\n      reinterpret_cast<decltype(this->error_init)>(\n          dlsym(library_, \"dbus_error_init\"));\n  if (!error_init) {\n    CleanUp(true);\n    return false;\n  }\n\n  error_is_set =\n      reinterpret_cast<decltype(this->error_is_set)>(\n          dlsym(library_, \"dbus_error_is_set\"));\n  if (!error_is_set) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_append_args =\n      reinterpret_cast<decltype(this->message_append_args)>(\n          dlsym(library_, \"dbus_message_append_args\"));\n  if (!message_append_args) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_get_interface =\n      reinterpret_cast<decltype(this->message_get_interface)>(\n          dlsym(library_, \"dbus_message_get_interface\"));\n  if (!message_get_interface) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_get_member =\n      reinterpret_cast<decltype(this->message_get_member)>(\n          dlsym(library_, \"dbus_message_get_member\"));\n  if (!message_get_member) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_is_signal =\n      reinterpret_cast<decltype(this->message_is_signal)>(\n          dlsym(library_, \"dbus_message_is_signal\"));\n  if (!message_is_signal) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_iter_get_arg_type =\n      reinterpret_cast<decltype(this->message_iter_get_arg_type)>(\n          dlsym(library_, \"dbus_message_iter_get_arg_type\"));\n  if (!message_iter_get_arg_type) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_iter_get_basic =\n      reinterpret_cast<decltype(this->message_iter_get_basic)>(\n          dlsym(library_, \"dbus_message_iter_get_basic\"));\n  if (!message_iter_get_basic) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_iter_init =\n      reinterpret_cast<decltype(this->message_iter_init)>(\n          dlsym(library_, \"dbus_message_iter_init\"));\n  if (!message_iter_init) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_iter_next =\n      reinterpret_cast<decltype(this->message_iter_next)>(\n          dlsym(library_, \"dbus_message_iter_next\"));\n  if (!message_iter_next) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_iter_recurse =\n      reinterpret_cast<decltype(this->message_iter_recurse)>(\n          dlsym(library_, \"dbus_message_iter_recurse\"));\n  if (!message_iter_recurse) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_new_method_call =\n      reinterpret_cast<decltype(this->message_new_method_call)>(\n          dlsym(library_, \"dbus_message_new_method_call\"));\n  if (!message_new_method_call) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_unref =\n      reinterpret_cast<decltype(this->message_unref)>(\n          dlsym(library_, \"dbus_message_unref\"));\n  if (!message_unref) {\n    CleanUp(true);\n    return false;\n  }\n\n  move_error =\n      reinterpret_cast<decltype(this->move_error)>(\n          dlsym(library_, \"dbus_move_error\"));\n  if (!move_error) {\n    CleanUp(true);\n    return false;\n  }\n\n  threads_init_default =\n      reinterpret_cast<decltype(this->threads_init_default)>(\n          dlsym(library_, \"dbus_threads_init_default\"));\n  if (!threads_init_default) {\n    CleanUp(true);\n    return false;\n  }\n\n  message_get_sender =\n      reinterpret_cast<decltype(this->message_get_sender)>(\n          dlsym(library_, \"dbus_message_get_sender\"));\n  if (!message_get_sender) {\n    CleanUp(true);\n    return false;\n  }\n\n#endif\n\n#if defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED)\n  bus_add_match = &::dbus_bus_add_match;\n  bus_get = &::dbus_bus_get;\n  bus_get_unique_name = &::dbus_bus_get_unique_name;\n  bus_remove_match = &::dbus_bus_remove_match;\n  connection_pop_message = &::dbus_connection_pop_message;\n  connection_read_write = &::dbus_connection_read_write;\n  connection_send_with_reply_and_block = &::dbus_connection_send_with_reply_and_block;\n  connection_unref = &::dbus_connection_unref;\n  error_free = &::dbus_error_free;\n  error_init = &::dbus_error_init;\n  error_is_set = &::dbus_error_is_set;\n  message_append_args = &::dbus_message_append_args;\n  message_is_signal = &::dbus_message_is_signal;\n  message_iter_get_arg_type = &::dbus_message_iter_get_arg_type;\n  message_iter_get_basic = &::dbus_message_iter_get_basic;\n  message_iter_init = &::dbus_message_iter_init;\n  message_iter_next = &::dbus_message_iter_next;\n  message_iter_recurse = &::dbus_message_iter_recurse;\n  message_new_method_call = &::dbus_message_new_method_call;\n  message_unref = &::dbus_message_unref;\n  move_error = &::dbus_move_error;\n  threads_init_default = &::dbus_threads_init_default;\n\n#endif\n\n  loaded_ = true;\n  return true;\n}\n\nvoid libdbus_loader::CleanUp(bool unload) {\n#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)\n  if (unload) {\n    dlclose(library_);\n    library_ = NULL;\n  }\n#endif\n  loaded_ = false;\n  bus_add_match = NULL;\n  bus_get = NULL;\n  bus_get_unique_name = NULL;\n  bus_remove_match = NULL;\n  connection_pop_message = NULL;\n  connection_read_write = NULL;\n  connection_send_with_reply_and_block = NULL;\n  connection_unref = NULL;\n  error_free = NULL;\n  error_init = NULL;\n  error_is_set = NULL;\n  message_append_args = NULL;\n  message_is_signal = NULL;\n  message_iter_get_arg_type = NULL;\n  message_iter_get_basic = NULL;\n  message_iter_init = NULL;\n  message_iter_next = NULL;\n  message_iter_recurse = NULL;\n  message_new_method_call = NULL;\n  message_unref = NULL;\n  move_error = NULL;\n  threads_init_default = NULL;\n\n}\n"
  },
  {
    "path": "src/loaders/loader_dbus.h",
    "content": "\n#ifndef LIBRARY_LOADER_DBUS_H\n#define LIBRARY_LOADER_DBUS_H\n\n#include <dbus/dbus.h>\n#define LIBRARY_LOADER_DBUS_H_DLOPEN\n\n\n#include <string>\n#include <dlfcn.h>\n\nclass libdbus_loader {\n public:\n  libdbus_loader();\n  libdbus_loader(const std::string& library_name) : libdbus_loader() {\n    Load(library_name);\n  }\n  ~libdbus_loader();\n\n  bool Load(const std::string& library_name);\n  bool IsLoaded() { return loaded_; }\n\n  decltype(&::dbus_bus_add_match) bus_add_match;\n  decltype(&::dbus_bus_get) bus_get;\n  decltype(&::dbus_bus_get_unique_name) bus_get_unique_name;\n  decltype(&::dbus_bus_remove_match) bus_remove_match;\n  decltype(&::dbus_connection_add_filter) connection_add_filter;\n  decltype(&::dbus_connection_pop_message) connection_pop_message;\n  decltype(&::dbus_connection_read_write) connection_read_write;\n  decltype(&::dbus_connection_read_write_dispatch) connection_read_write_dispatch;\n  decltype(&::dbus_connection_remove_filter) connection_remove_filter;\n  decltype(&::dbus_connection_send_with_reply_and_block) connection_send_with_reply_and_block;\n  decltype(&::dbus_connection_unref) connection_unref;\n  decltype(&::dbus_error_free) error_free;\n  decltype(&::dbus_error_init) error_init;\n  decltype(&::dbus_error_is_set) error_is_set;\n  decltype(&::dbus_message_append_args) message_append_args;\n  decltype(&::dbus_message_get_sender) message_get_sender;\n  decltype(&::dbus_message_get_interface) message_get_interface;\n  decltype(&::dbus_message_get_member) message_get_member;\n  decltype(&::dbus_message_is_signal) message_is_signal;\n  decltype(&::dbus_message_iter_get_arg_type) message_iter_get_arg_type;\n  decltype(&::dbus_message_iter_get_basic) message_iter_get_basic;\n  decltype(&::dbus_message_iter_init) message_iter_init;\n  decltype(&::dbus_message_iter_next) message_iter_next;\n  decltype(&::dbus_message_iter_recurse) message_iter_recurse;\n  decltype(&::dbus_message_new_method_call) message_new_method_call;\n  decltype(&::dbus_message_unref) message_unref;\n  decltype(&::dbus_move_error) move_error;\n  decltype(&::dbus_threads_init_default) threads_init_default;\n\n\n private:\n  void CleanUp(bool unload);\n\n#if defined(LIBRARY_LOADER_DBUS_H_DLOPEN)\n  void* library_;\n#endif\n\n  bool loaded_;\n\n  // Disallow copy constructor and assignment operator.\n  libdbus_loader(const libdbus_loader&);\n  void operator=(const libdbus_loader&);\n};\n\n#endif  // LIBRARY_LOADER_DBUS_H\n"
  },
  {
    "path": "src/loaders/loader_glx.cpp",
    "content": "#include <iostream>\n#include <spdlog/spdlog.h>\n#include \"real_dlsym.h\"\n#include \"loaders/loader_glx.h\"\n\nglx_loader::glx_loader() : loaded_(false) {\n}\n\nglx_loader::~glx_loader() {\n  CleanUp(loaded_);\n}\n\nbool glx_loader::Load() {\n  if (loaded_) {\n    return true;\n  }\n\n  // Force load libGL\n  void *handle = nullptr;\n#ifndef NDEBUG\n  // Use apitrace's glxtrace.so for debugging\n  // Assumes glxtrace.so lives outside of usual library paths and is only preloaded\n  handle = real_dlopen(\"glxtrace.so\", RTLD_LAZY);\n#endif\n  if (!handle)\n    handle = real_dlopen(\"libGL.so.1\", RTLD_LAZY);\n  if (!handle) {\n    SPDLOG_ERROR(\"Failed to open \" MANGOHUD_ARCH \" libGL.so.1: {}\", dlerror());\n    return false;\n  }\n\n  GetProcAddress =\n      reinterpret_cast<decltype(this->GetProcAddress)>(\n          real_dlsym(handle, \"glXGetProcAddress\"));\n\n  GetProcAddressARB =\n      reinterpret_cast<decltype(this->GetProcAddressARB)>(\n          real_dlsym(handle, \"glXGetProcAddressARB\"));\n\n  if (!GetProcAddress) {\n    CleanUp(true);\n    return false;\n  }\n\n  CreateContext =\n      reinterpret_cast<decltype(this->CreateContext)>(\n          GetProcAddress((const unsigned char *)\"glXCreateContext\"));\n  if (!CreateContext) {\n    CleanUp(true);\n    return false;\n  }\n\n  CreateContextAttribs =\n      reinterpret_cast<decltype(this->CreateContextAttribs)>(\n          GetProcAddress((const unsigned char *)\"glXCreateContextAttribs\"));\n//   if (!CreateContextAttribs) {\n//     CleanUp(true);\n//     return false;\n//   }\n\n  CreateContextAttribsARB =\n      reinterpret_cast<decltype(this->CreateContextAttribsARB)>(\n          GetProcAddress((const unsigned char *)\"glXCreateContextAttribsARB\"));\n//   if (!CreateContextAttribsARB) {\n//     CleanUp(true);\n//     return false;\n//   }\n\n  DestroyContext =\n      reinterpret_cast<decltype(this->DestroyContext)>(\n          GetProcAddress((const unsigned char *)\"glXDestroyContext\"));\n  if (!DestroyContext) {\n    CleanUp(true);\n    return false;\n  }\n\n  GetCurrentContext =\n      reinterpret_cast<decltype(this->GetCurrentContext)>(\n          GetProcAddress((const unsigned char *)\"glXGetCurrentContext\"));\n  if (!GetCurrentContext) {\n    CleanUp(true);\n    return false;\n  }\n\n  GetCurrentDrawable =\n      reinterpret_cast<decltype(this->GetCurrentDrawable)>(\n          GetProcAddress((const unsigned char *)\"glXGetCurrentDrawable\"));\n  if (!GetCurrentDrawable) {\n    CleanUp(true);\n    return false;\n  }\n\n  GetCurrentReadDrawable =\n      reinterpret_cast<decltype(this->GetCurrentReadDrawable)>(\n          GetProcAddress((const unsigned char *)\"glXGetCurrentReadDrawable\"));\n\n  SwapBuffers =\n      reinterpret_cast<decltype(this->SwapBuffers)>(\n          GetProcAddress((const unsigned char *)\"glXSwapBuffers\"));\n  if (!SwapBuffers) {\n    CleanUp(true);\n    return false;\n  }\n\n  SwapBuffersMscOML =\n      reinterpret_cast<decltype(this->SwapBuffersMscOML)>(\n          GetProcAddress((const unsigned char *)\"glXSwapBuffersMscOML\"));\n  /*if (!SwapBuffersMscOML) {\n    CleanUp(true);\n    return false;\n  }*/\n\n  SwapIntervalEXT =\n      reinterpret_cast<decltype(this->SwapIntervalEXT)>(\n          GetProcAddress((const unsigned char *)\"glXSwapIntervalEXT\"));\n\n  SwapIntervalSGI =\n      reinterpret_cast<decltype(this->SwapIntervalSGI)>(\n          GetProcAddress((const unsigned char *)\"glXSwapIntervalSGI\"));\n\n  SwapIntervalMESA =\n      reinterpret_cast<decltype(this->SwapIntervalMESA)>(\n          GetProcAddress((const unsigned char *)\"glXSwapIntervalMESA\"));\n\n  GetSwapIntervalMESA =\n      reinterpret_cast<decltype(this->GetSwapIntervalMESA)>(\n          GetProcAddress((const unsigned char *)\"glXGetSwapIntervalMESA\"));\n\n  QueryDrawable =\n      reinterpret_cast<decltype(this->QueryDrawable)>(\n          GetProcAddress((const unsigned char *)\"glXQueryDrawable\"));\n\n  MakeContextCurrent =\n      reinterpret_cast<decltype(this->MakeContextCurrent)>(\n          GetProcAddress((const unsigned char *)\"glXMakeContextCurrent\"));\n\n  MakeCurrent =\n      reinterpret_cast<decltype(this->MakeCurrent)>(\n          GetProcAddress((const unsigned char *)\"glXMakeCurrent\"));\n  if (!MakeCurrent) {\n    CleanUp(true);\n    return false;\n  }\n\n  loaded_ = true;\n  return true;\n}\n\nvoid glx_loader::CleanUp(bool unload) {\n  loaded_ = false;\n  GetProcAddress = nullptr;\n  GetProcAddressARB = nullptr;\n  CreateContext = nullptr;\n  DestroyContext = nullptr;\n  SwapBuffers = nullptr;\n  SwapIntervalEXT = nullptr;\n  SwapIntervalSGI = nullptr;\n  SwapIntervalMESA = nullptr;\n  QueryDrawable = nullptr;\n  MakeContextCurrent = nullptr;\n  MakeCurrent = nullptr;\n}\n\nglx_loader glx;\n"
  },
  {
    "path": "src/loaders/loader_glx.h",
    "content": "#pragma once\n#include \"gl/gl.h\"\n#include <dlfcn.h>\n\nclass glx_loader {\n public:\n  glx_loader();\n  ~glx_loader();\n\n  bool Load();\n  bool IsLoaded() { return loaded_; }\n\n  decltype(&::glXGetProcAddress) GetProcAddress;\n  decltype(&::glXGetProcAddressARB) GetProcAddressARB;\n  decltype(&::glXCreateContext) CreateContext;\n  decltype(&::glXCreateContextAttribsARB) CreateContextAttribs;\n  decltype(&::glXCreateContextAttribsARB) CreateContextAttribsARB;\n  decltype(&::glXDestroyContext) DestroyContext;\n  decltype(&::glXGetCurrentDrawable) GetCurrentDrawable;\n  decltype(&::glXGetCurrentReadDrawable) GetCurrentReadDrawable;\n  decltype(&::glXSwapBuffers) SwapBuffers;\n  decltype(&::glXSwapIntervalEXT) SwapIntervalEXT;\n  decltype(&::glXSwapIntervalSGI) SwapIntervalSGI;\n  decltype(&::glXSwapIntervalMESA) SwapIntervalMESA;\n  decltype(&::glXGetSwapIntervalMESA) GetSwapIntervalMESA;\n  decltype(&::glXMakeContextCurrent) MakeContextCurrent;\n  decltype(&::glXMakeCurrent) MakeCurrent;\n  decltype(&::glXGetCurrentContext) GetCurrentContext;\n  decltype(&::glXQueryDrawable) QueryDrawable;\n  decltype(&::glXSwapBuffersMscOML) SwapBuffersMscOML;\n\n private:\n  void CleanUp(bool unload);\n\n  bool loaded_;\n\n  // Disallow copy constructor and assignment operator.\n  glx_loader(const glx_loader&);\n  void operator=(const glx_loader&);\n};\n"
  },
  {
    "path": "src/loaders/loader_nvctrl.cpp",
    "content": "#include \"loader_nvctrl.h\"\n#include <iostream>\n#include <spdlog/spdlog.h>\n\n// Put these sanity checks here so that they fire at most once\n// (to avoid cluttering the build output).\n#if !defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && !defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED)\n#error neither LIBRARY_LOADER_NVCTRL_H_DLOPEN nor LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined\n#endif\n#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED)\n#error both LIBRARY_LOADER_NVCTRL_H_DLOPEN and LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined\n#endif\n\nstatic std::shared_ptr<libnvctrl_loader> libnvctrl_;\n\nstd::shared_ptr<libnvctrl_loader> get_libnvctrl_loader()\n{\n    if (!libnvctrl_)\n        libnvctrl_ = std::make_shared<libnvctrl_loader>(\"libXNVCtrl.so.0\");\n    return libnvctrl_;\n}\n\nlibnvctrl_loader::libnvctrl_loader() : loaded_(false) {\n}\n\nlibnvctrl_loader::~libnvctrl_loader() {\n  CleanUp(loaded_);\n}\n\nbool libnvctrl_loader::Load(const std::string& library_name) {\n  if (loaded_) {\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN)\n  library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE);\n  if (!library_) {\n    SPDLOG_DEBUG(\"Failed to open \" MANGOHUD_ARCH \" {}: {}\", library_name, dlerror());\n    return false;\n  }\n\n  XNVCTRLIsNvScreen =\n      reinterpret_cast<decltype(this->XNVCTRLIsNvScreen)>(\n          dlsym(library_, \"XNVCTRLIsNvScreen\"));\n  if (!XNVCTRLIsNvScreen) {\n    CleanUp(true);\n    return false;\n  }\n\n  XNVCTRLQueryVersion =\n      reinterpret_cast<decltype(this->XNVCTRLQueryVersion)>(\n          dlsym(library_, \"XNVCTRLQueryVersion\"));\n  if (!XNVCTRLQueryVersion) {\n    CleanUp(true);\n    return false;\n  }\n\n  XNVCTRLQueryAttribute =\n      reinterpret_cast<decltype(this->XNVCTRLQueryAttribute)>(\n          dlsym(library_, \"XNVCTRLQueryAttribute\"));\n  if (!XNVCTRLQueryAttribute) {\n    CleanUp(true);\n    return false;\n  }\n\n  XNVCTRLQueryTargetStringAttribute =\n      reinterpret_cast<decltype(this->XNVCTRLQueryTargetStringAttribute)>(\n          dlsym(library_, \"XNVCTRLQueryTargetStringAttribute\"));\n  if (!XNVCTRLQueryTargetStringAttribute) {\n    CleanUp(true);\n    return false;\n  }\n\n  XNVCTRLQueryTargetAttribute64 =\n      reinterpret_cast<decltype(this->XNVCTRLQueryTargetAttribute64)>(\n          dlsym(library_, \"XNVCTRLQueryTargetAttribute64\"));\n  if (!XNVCTRLQueryTargetAttribute64) {\n    CleanUp(true);\n    return false;\n  }\n\n  XNVCTRLQueryTargetCount =\n      reinterpret_cast<decltype(this->XNVCTRLQueryTargetCount)>(\n          dlsym(library_, \"XNVCTRLQueryTargetCount\"));\n  if (!XNVCTRLQueryTargetCount) {\n    CleanUp(true);\n    return false;\n  }\n\n#endif\n\n#if defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED)\n  XNVCTRLQueryVersion = &::XNVCTRLQueryVersion;\n  XNVCTRLQueryAttribute = &::XNVCTRLQueryAttribute;\n\n#endif\n\n  loaded_ = true;\n  return true;\n}\n\nvoid libnvctrl_loader::CleanUp(bool unload) {\n#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN)\n  if (unload) {\n    dlclose(library_);\n    library_ = NULL;\n  }\n#endif\n  loaded_ = false;\n  XNVCTRLQueryVersion = NULL;\n  XNVCTRLQueryAttribute = NULL;\n\n}\n"
  },
  {
    "path": "src/loaders/loader_nvctrl.h",
    "content": "#pragma once\n#ifndef LIBRARY_LOADER_NVCTRL_H\n#define LIBRARY_LOADER_NVCTRL_H\n// #define Bool bool\n#include <X11/Xlib.h>\n#include \"NVCtrl/NVCtrlLib.h\"\n#define LIBRARY_LOADER_NVCTRL_H_DLOPEN\n\n#include <string>\n#include <dlfcn.h>\n#include <memory>\n\nclass libnvctrl_loader {\n public:\n  libnvctrl_loader();\n  libnvctrl_loader(const std::string& library_name) : libnvctrl_loader() {\n    Load(library_name);\n  }\n  ~libnvctrl_loader();\n\n  bool Load(const std::string& library_name);\n  bool IsLoaded() { return loaded_; }\n\n  decltype(&::XNVCTRLIsNvScreen) XNVCTRLIsNvScreen;\n  decltype(&::XNVCTRLQueryVersion) XNVCTRLQueryVersion;\n  decltype(&::XNVCTRLQueryAttribute) XNVCTRLQueryAttribute;\n  decltype(&::XNVCTRLQueryTargetStringAttribute) XNVCTRLQueryTargetStringAttribute;\n  decltype(&::XNVCTRLQueryTargetAttribute64) XNVCTRLQueryTargetAttribute64;\n  decltype(&::XNVCTRLQueryTargetCount) XNVCTRLQueryTargetCount;\n\n private:\n  void CleanUp(bool unload);\n\n#if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN)\n  void* library_;\n#endif\n\n  bool loaded_;\n\n  // Disallow copy constructor and assignment operator.\n  libnvctrl_loader(const libnvctrl_loader&);\n  void operator=(const libnvctrl_loader&);\n};\n\nstd::shared_ptr<libnvctrl_loader> get_libnvctrl_loader();\n#endif  // LIBRARY_LOADER_NVCTRL_H\n"
  },
  {
    "path": "src/loaders/loader_nvml.cpp",
    "content": "// This is generated file. Do not modify directly.\n// Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py .\n\n#include \"loader_nvml.h\"\n#include <iostream>\n#include <spdlog/spdlog.h>\n\n// Put these sanity checks here so that they fire at most once\n// (to avoid cluttering the build output).\n#if !defined(LIBRARY_LOADER_NVML_H_DLOPEN) && !defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n#error neither LIBRARY_LOADER_NVML_H_DLOPEN nor LIBRARY_LOADER_NVML_H_DT_NEEDED defined\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN) && defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n#error both LIBRARY_LOADER_NVML_H_DLOPEN and LIBRARY_LOADER_NVML_H_DT_NEEDED defined\n#endif\n\nstatic std::shared_ptr<libnvml_loader> libnvml_;\n\nstd::shared_ptr<libnvml_loader> get_libnvml_loader()\n{\n    if (!libnvml_)\n        libnvml_ = std::make_shared<libnvml_loader>(\"libnvidia-ml.so.1\");\n    return libnvml_;\n}\n\nlibnvml_loader::libnvml_loader() : loaded_(false) {\n}\n\nlibnvml_loader::~libnvml_loader() {\n  CleanUp(loaded_);\n}\n\nbool libnvml_loader::Load(const std::string& library_name) {\n  if (loaded_) {\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE);\n  if (!library_) {\n    SPDLOG_ERROR(\"Failed to open \" MANGOHUD_ARCH \" {}: {}\", library_name, dlerror());\n    return false;\n  }\n#endif\n\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlInit_v2 =\n      reinterpret_cast<decltype(this->nvmlInit_v2)>(\n          dlsym(library_, \"nvmlInit_v2\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlInit_v2 = &::nvmlInit_v2;\n#endif\n  if (!nvmlInit_v2) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlShutdown =\n      reinterpret_cast<decltype(this->nvmlShutdown)>(\n          dlsym(library_, \"nvmlShutdown\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlShutdown = &::nvmlShutdown;\n#endif\n  if (!nvmlShutdown) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetUtilizationRates =\n      reinterpret_cast<decltype(this->nvmlDeviceGetUtilizationRates)>(\n          dlsym(library_, \"nvmlDeviceGetUtilizationRates\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetUtilizationRates = &::nvmlDeviceGetUtilizationRates;\n#endif\n  if (!nvmlDeviceGetUtilizationRates) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetTemperature =\n      reinterpret_cast<decltype(this->nvmlDeviceGetTemperature)>(\n          dlsym(library_, \"nvmlDeviceGetTemperature\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetTemperature = &::nvmlDeviceGetTemperature;\n#endif\n  if (!nvmlDeviceGetTemperature) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetPciInfo_v3 =\n      reinterpret_cast<decltype(this->nvmlDeviceGetPciInfo_v3)>(\n          dlsym(library_, \"nvmlDeviceGetPciInfo_v3\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetPciInfo_v3 = &::nvmlDeviceGetPciInfo_v3;\n#endif\n  if (!nvmlDeviceGetPciInfo_v3) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetCount_v2 =\n      reinterpret_cast<decltype(this->nvmlDeviceGetCount_v2)>(\n          dlsym(library_, \"nvmlDeviceGetCount_v2\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetCount_v2 = &::nvmlDeviceGetCount_v2;\n#endif\n  if (!nvmlDeviceGetCount_v2) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetHandleByIndex_v2 =\n      reinterpret_cast<decltype(this->nvmlDeviceGetHandleByIndex_v2)>(\n          dlsym(library_, \"nvmlDeviceGetHandleByIndex_v2\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetHandleByIndex_v2 = &::nvmlDeviceGetHandleByIndex_v2;\n#endif\n  if (!nvmlDeviceGetHandleByIndex_v2) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetHandleByPciBusId_v2 =\n      reinterpret_cast<decltype(this->nvmlDeviceGetHandleByPciBusId_v2)>(\n          dlsym(library_, \"nvmlDeviceGetHandleByPciBusId_v2\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetHandleByPciBusId_v2 = &::nvmlDeviceGetHandleByPciBusId_v2;\n#endif\n  if (!nvmlDeviceGetHandleByPciBusId_v2) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetMemoryInfo =\n      reinterpret_cast<decltype(this->nvmlDeviceGetMemoryInfo)>(\n          dlsym(library_, \"nvmlDeviceGetMemoryInfo\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetMemoryInfo = &::nvmlDeviceGetMemoryInfo;\n#endif\n  if (!nvmlDeviceGetMemoryInfo) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetClockInfo =\n      reinterpret_cast<decltype(this->nvmlDeviceGetClockInfo)>(\n          dlsym(library_, \"nvmlDeviceGetClockInfo\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetClockInfo = &::nvmlDeviceGetClockInfo;\n#endif\n  if (!nvmlDeviceGetClockInfo) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlErrorString =\n      reinterpret_cast<decltype(this->nvmlErrorString)>(\n          dlsym(library_, \"nvmlErrorString\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlErrorString = &::nvmlErrorString;\n#endif\n  if (!nvmlErrorString) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetCurrentClocksThrottleReasons =\n      reinterpret_cast<decltype(this->nvmlDeviceGetCurrentClocksThrottleReasons)>(\n          dlsym(library_, \"nvmlDeviceGetCurrentClocksThrottleReasons\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetCurrentClocksThrottleReasons = &::nvmlDeviceGetCurrentClocksThrottleReasons;\n#endif\n  if (!nvmlErrorString) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetPowerUsage =\n      reinterpret_cast<decltype(this->nvmlDeviceGetPowerUsage)>(\n          dlsym(library_, \"nvmlDeviceGetPowerUsage\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetPowerUsage = &::nvmlDeviceGetPowerUsage;\n#endif\n  if (!nvmlDeviceGetPowerUsage) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetPowerManagementLimit =\n      reinterpret_cast<decltype(this->nvmlDeviceGetPowerManagementLimit)>(\n          dlsym(library_, \"nvmlDeviceGetPowerManagementLimit\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetPowerManagementLimit = &::nvmlDeviceGetPowerManagementLimit;\n#endif\n  if (!nvmlDeviceGetPowerManagementLimit) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlUnitGetFanSpeedInfo =\n      reinterpret_cast<decltype(this->nvmlUnitGetFanSpeedInfo)>(\n          dlsym(library_, \"nvmlUnitGetFanSpeedInfo\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlUnitGetFanSpeedInfo = &::nvmlUnitGetFanSpeedInfo;\n#endif\n  if (!nvmlUnitGetFanSpeedInfo) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlUnitGetHandleByIndex =\n      reinterpret_cast<decltype(this->nvmlUnitGetHandleByIndex)>(\n          dlsym(library_, \"nvmlUnitGetHandleByIndex\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlUnitGetHandleByIndex = &::nvmlUnitGetHandleByIndex;\n#endif\n  if (!nvmlUnitGetHandleByIndex) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetFanSpeed =\n      reinterpret_cast<decltype(this->nvmlDeviceGetFanSpeed)>(\n          dlsym(library_, \"nvmlDeviceGetFanSpeed\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetFanSpeed = &::nvmlDeviceGetFanSpeed;\n#endif\n  if (!nvmlDeviceGetFanSpeed) {\n    CleanUp(true);\n    return false;\n  }\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  nvmlDeviceGetGraphicsRunningProcesses =\n      reinterpret_cast<decltype(this->nvmlDeviceGetGraphicsRunningProcesses)>(\n          dlsym(library_, \"nvmlDeviceGetGraphicsRunningProcesses\"));\n#endif\n#if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED)\n  nvmlDeviceGetGraphicsRunningProcesses = &::nvmlDeviceGetGraphicsRunningProcesses;\n#endif\n  if (!nvmlDeviceGetGraphicsRunningProcesses) {\n    CleanUp(true);\n    return false;\n  }\n\n  loaded_ = true;\n  return true;\n}\n\n\nvoid libnvml_loader::CleanUp(bool unload) {\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  if (unload) {\n    dlclose(library_);\n    library_ = NULL;\n  }\n#endif\n  loaded_ = false;\n  nvmlInit_v2 = NULL;\n  nvmlShutdown = NULL;\n  nvmlDeviceGetUtilizationRates = NULL;\n  nvmlDeviceGetTemperature = NULL;\n  nvmlDeviceGetPciInfo_v3 = NULL;\n  nvmlDeviceGetCount_v2 = NULL;\n  nvmlDeviceGetHandleByIndex_v2 = NULL;\n  nvmlDeviceGetHandleByPciBusId_v2 = NULL;\n  nvmlDeviceGetCurrentClocksThrottleReasons = NULL;\n  nvmlUnitGetFanSpeedInfo = NULL;\n  nvmlUnitGetHandleByIndex = NULL;\n  nvmlDeviceGetFanSpeed = NULL;\n  nvmlDeviceGetGraphicsRunningProcesses = NULL;\n}\n"
  },
  {
    "path": "src/loaders/loader_nvml.h",
    "content": "// This is generated file. Do not modify directly.\n// Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py .\n\n#ifndef LIBRARY_LOADER_NVML_H\n#define LIBRARY_LOADER_NVML_H\n\n#if USE_SYSTEM_NVML\n#include <nvml.h>\n#else\n#include \"nvml.h\"\ntypedef nvmlProcessInfo_t nvmlProcessInfo_v1_t;\n#endif\n#define LIBRARY_LOADER_NVML_H_DLOPEN\n\n#include <string>\n#include <dlfcn.h>\n#include <memory>\n\nclass libnvml_loader {\n public:\n  libnvml_loader();\n  libnvml_loader(const std::string& library_name) : libnvml_loader() {\n    Load(library_name);\n  }\n  ~libnvml_loader();\n\n  bool Load(const std::string& library_name);\n  bool IsLoaded() { return loaded_; }\n\n  decltype(&::nvmlInit_v2) nvmlInit_v2;\n  decltype(&::nvmlShutdown) nvmlShutdown;\n  decltype(&::nvmlDeviceGetUtilizationRates) nvmlDeviceGetUtilizationRates;\n  decltype(&::nvmlDeviceGetTemperature) nvmlDeviceGetTemperature;\n  decltype(&::nvmlDeviceGetPciInfo_v3) nvmlDeviceGetPciInfo_v3;\n  decltype(&::nvmlDeviceGetCount_v2) nvmlDeviceGetCount_v2;\n  decltype(&::nvmlDeviceGetHandleByIndex_v2) nvmlDeviceGetHandleByIndex_v2;\n  decltype(&::nvmlDeviceGetHandleByPciBusId_v2) nvmlDeviceGetHandleByPciBusId_v2;\n  decltype(&::nvmlDeviceGetMemoryInfo) nvmlDeviceGetMemoryInfo;\n  decltype(&::nvmlDeviceGetClockInfo) nvmlDeviceGetClockInfo;\n  decltype(&::nvmlErrorString) nvmlErrorString;\n  decltype(&::nvmlDeviceGetPowerUsage) nvmlDeviceGetPowerUsage;\n  decltype(&::nvmlDeviceGetPowerManagementLimit) nvmlDeviceGetPowerManagementLimit;\n  decltype(&::nvmlDeviceGetCurrentClocksThrottleReasons) nvmlDeviceGetCurrentClocksThrottleReasons;\n  decltype(&::nvmlUnitGetFanSpeedInfo) nvmlUnitGetFanSpeedInfo;\n  decltype(&::nvmlUnitGetHandleByIndex) nvmlUnitGetHandleByIndex;\n  decltype(&::nvmlDeviceGetFanSpeed) nvmlDeviceGetFanSpeed;\n  decltype(&::nvmlDeviceGetGraphicsRunningProcesses) nvmlDeviceGetGraphicsRunningProcesses;\n\n private:\n  void CleanUp(bool unload);\n\n#if defined(LIBRARY_LOADER_NVML_H_DLOPEN)\n  void* library_ = nullptr;\n#endif\n\n  bool loaded_;\n\n  // Disallow copy constructor and assignment operator.\n  libnvml_loader(const libnvml_loader&);\n  void operator=(const libnvml_loader&);\n};\n\nstd::shared_ptr<libnvml_loader> get_libnvml_loader();\n#endif  // LIBRARY_LOADER_NVML_H\n"
  },
  {
    "path": "src/loaders/loader_x11.cpp",
    "content": "#include \"loader_x11.h\"\n#include <iostream>\n#include <spdlog/spdlog.h>\n\nlibx11_loader::libx11_loader() : loaded_(false) {\n}\n\nlibx11_loader::~libx11_loader() {\n  CleanUp(loaded_);\n}\n\nbool libx11_loader::Load(const std::string& library_name) {\n  if (loaded_) {\n    return false;\n  }\n\n  library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE);\n  if (!library_) {\n    SPDLOG_ERROR(\"Failed to open \" MANGOHUD_ARCH \" {}: {}\", library_name, dlerror());\n    return false;\n  }\n\n\n  XOpenDisplay =\n      reinterpret_cast<decltype(this->XOpenDisplay)>(\n          dlsym(library_, \"XOpenDisplay\"));\n  if (!XOpenDisplay) {\n    CleanUp(true);\n    return false;\n  }\n\n  XCloseDisplay =\n      reinterpret_cast<decltype(this->XCloseDisplay)>(\n          dlsym(library_, \"XCloseDisplay\"));\n  if (!XCloseDisplay) {\n    CleanUp(true);\n    return false;\n  }\n\n  XDefaultScreen =\n      reinterpret_cast<decltype(this->XDefaultScreen)>(\n          dlsym(library_, \"XDefaultScreen\"));\n  if (!XDefaultScreen) {\n      CleanUp(true);\n      return false;\n  }\n\n  XQueryKeymap =\n      reinterpret_cast<decltype(this->XQueryKeymap)>(\n          dlsym(library_, \"XQueryKeymap\"));\n  if (!XQueryKeymap) {\n    CleanUp(true);\n    return false;\n  }\n\n  XKeysymToKeycode =\n      reinterpret_cast<decltype(this->XKeysymToKeycode)>(\n          dlsym(library_, \"XKeysymToKeycode\"));\n  if (!XKeysymToKeycode) {\n    CleanUp(true);\n    return false;\n  }\n\n  XStringToKeysym =\n      reinterpret_cast<decltype(this->XStringToKeysym)>(\n          dlsym(library_, \"XStringToKeysym\"));\n  if (!XStringToKeysym) {\n    CleanUp(true);\n    return false;\n  }\n\n  XGetGeometry =\n      reinterpret_cast<decltype(this->XGetGeometry)>(\n          dlsym(library_, \"XGetGeometry\"));\n  if (!XGetGeometry) {\n    CleanUp(true);\n    return false;\n  }\n\n  XQueryExtension =\n      reinterpret_cast<decltype(this->XQueryExtension)>(\n          dlsym(library_, \"XQueryExtension\"));\n  if (!XQueryExtension) {\n    CleanUp(true);\n    return false;\n  }\n\n  loaded_ = true;\n  return true;\n}\n\nvoid libx11_loader::CleanUp(bool unload) {\n  if (unload) {\n    dlclose(library_);\n    library_ = NULL;\n  }\n\n  loaded_ = false;\n  XOpenDisplay = NULL;\n  XCloseDisplay = NULL;\n  XQueryKeymap = NULL;\n  XKeysymToKeycode = NULL;\n  XStringToKeysym = NULL;\n  XGetGeometry = NULL;\n  XQueryExtension = NULL;\n\n}\n\nstatic std::shared_ptr<libx11_loader> loader;\nstd::shared_ptr<libx11_loader> get_libx11()\n{\n    if (!loader)\n        loader = std::make_shared<libx11_loader>(\"libX11.so.6\");\n    return loader;\n}\n"
  },
  {
    "path": "src/loaders/loader_x11.h",
    "content": "#pragma once\n#include <X11/Xlib.h>\n#include <memory>\n\n#include <string>\n#include <dlfcn.h>\n\nclass libx11_loader {\n public:\n  libx11_loader();\n  libx11_loader(const std::string& library_name) { Load(library_name); }\n  ~libx11_loader();\n\n  bool Load(const std::string& library_name);\n  bool IsLoaded() { return loaded_; }\n\n  decltype(&::XOpenDisplay) XOpenDisplay;\n  decltype(&::XCloseDisplay) XCloseDisplay;\n  decltype(&::XDefaultScreen) XDefaultScreen;\n  decltype(&::XQueryKeymap) XQueryKeymap;\n  decltype(&::XKeysymToKeycode) XKeysymToKeycode;\n  decltype(&::XStringToKeysym) XStringToKeysym;\n  decltype(&::XGetGeometry) XGetGeometry;\n  decltype(&::XQueryExtension) XQueryExtension;\n\n\n private:\n  void CleanUp(bool unload);\n\n  void* library_ = nullptr;\n  bool loaded_ = false;\n\n  // Disallow copy constructor and assignment operator.\n  libx11_loader(const libx11_loader&);\n  void operator=(const libx11_loader&);\n};\n\nstd::shared_ptr<libx11_loader> get_libx11();\n"
  },
  {
    "path": "src/logging.cpp",
    "content": "#include <sstream>\n#include <iomanip>\n#include <array>\n#include <algorithm>\n#include <spdlog/spdlog.h>\n#include \"logging.h\"\n#include \"overlay.h\"\n#include \"config.h\"\n#include \"file_utils.h\"\n#include \"string_utils.h\"\n#include \"version.h\"\n#include \"fps_metrics.h\"\n\nusing namespace std;\n\nstring os, cpu, gpu, ram, kernel, driver, cpusched;\nbool sysInfoFetched = false;\ndouble fps;\nfloat frametime;\nlogData currentLogData = {};\nstd::shared_ptr<Logger> logger;\nofstream output_file;\nstd::thread log_thread;\n\nstring exec(string command) {\n#ifndef _WIN32\n    command = \"unset LD_PRELOAD; \" + command;\n#endif\n    std::array<char, 128> buffer;\n    std::string result;\n    auto deleter = [](FILE* ptr){ pclose(ptr); };\n    std::unique_ptr<FILE, decltype(deleter)> pipe(popen(command.c_str(), \"r\"), deleter);\n    if (!pipe) {\n      return \"popen failed!\";\n    }\n    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {\n      result += buffer.data();\n    }\n    return result;\n}\n\nstatic void upload_file(std::string logFile){\n  std::string command = \"curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' \";\n  command += \" -F 'log[uploads][]=@\" + logFile + \"'\";\n\n  command += \" | grep Location | cut -c11-\";\n  std::string url = exec(command);\n  std::cout << \"upload url: \" << url;\n  exec(\"xdg-open \" + url);\n}\n\nstatic void upload_files(const std::vector<std::string>& logFiles){\n  std::string command = \"curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' \";\n  for (auto& file : logFiles)\n    command += \" -F 'log[uploads][]=@\" + file + \"'\";\n\n  command += \" | grep Location | cut -c11-\";\n  std::string url = exec(command);\n  std::cout << \"upload url: \" << url;\n  exec(\"xdg-open \" + url);\n}\n\nstatic bool compareByFps(const logData &a, const logData &b)\n{\n    return a.fps < b.fps;\n}\n\nstatic void writeSummary(string filename){\n  auto& logArray = logger->get_log_data();\n  // if the log is stopped/started too fast we might end up with an empty vector.\n  // in that case, just bail.\n  if (logArray.size() == 0){\n    logger->stop_logging();\n    return;\n  }\n\n  filename = filename.substr(0, filename.size() - 4);\n  filename += \"_summary.csv\";\n  SPDLOG_INFO(\"{}\", filename);\n  SPDLOG_DEBUG(\"Writing summary log file [{}]\", filename);\n  std::ofstream out(filename, ios::out | ios::app);\n  if (out){\n    out << \"0.1% Min FPS,\" << \"1% Min FPS,\" << \"97% Percentile FPS,\" \n        << \"Average FPS,\" << \"GPU Load,\" << \"CPU Load,\" << \"Average Frame Time,\"\n        << \"Average GPU Temp,\" << \"Average CPU Temp,\" << \"Average VRAM Used,\"\n        << \"Average RAM Used,\" << \"Average Swap Used,\" << \"Peak GPU Load,\"\n        << \"Peak CPU Load,\" << \"Peak GPU Temp,\" << \"Peak CPU Temp,\"\n        << \"Peak VRAM Used,\" << \"Peak RAM Used,\" << \"Peak Swap Used\" << \"\\n\";\n    std::vector<logData> sorted = logArray;\n    std::sort(sorted.begin(), sorted.end(), compareByFps);\n    float total = 0.0f;\n    float total_gpu = 0.0f;\n    float total_cpu = 0.0f;\n    int total_gpu_temp = 0.0f;\n    int total_cpu_temp = 0.0f;\n    float total_vram = 0.0f;\n    float total_ram = 0.0f;\n    float total_swap = 0.0f;\n    int peak_gpu = 0.0f;\n    float peak_cpu = 0.0f;\n    int peak_gpu_temp = 0.0f;\n    int peak_cpu_temp = 0.0f;\n    float peak_vram = 0.0f;\n    float peak_ram = 0.0f;\n    float peak_swap = 0.0f;\n    float result;\n    std::vector<float> fps_values;\n    for (auto& data : sorted)\n      fps_values.push_back(data.frametime);\n\n    std::unique_ptr<fpsMetrics> fpsmetrics;\n    std::vector<std::string> metrics {\"0.001\", \"0.01\", \"0.97\"};\n    fpsmetrics = std::make_unique<fpsMetrics>(metrics, fps_values);\n    auto metrics_copy = fpsmetrics->copy_metrics();\n    for (auto& metric : metrics_copy)\n      out << metric.value << \",\";\n\n    fpsmetrics.reset();\n\n    total = 0;\n    for (auto input : sorted){\n      total = total + input.frametime;\n      total_gpu = total_gpu + input.gpu_load;\n      total_cpu = total_cpu + input.cpu_load;\n      total_gpu_temp = total_gpu_temp + input.gpu_temp;\n      total_cpu_temp = total_cpu_temp + input.cpu_temp;\n      total_vram = total_vram + input.gpu_vram_used;\n      total_ram = total_ram + input.ram_used;\n      total_swap = total_swap + input.swap_used;\n      peak_gpu = std::max(peak_gpu, input.gpu_load);\n      peak_cpu = std::max(peak_cpu, input.cpu_load);\n      peak_gpu_temp = std::max(peak_gpu_temp, input.gpu_temp);\n      peak_cpu_temp = std::max(peak_cpu_temp, input.cpu_temp);\n      peak_vram = std::max(peak_vram, input.gpu_vram_used);\n      peak_ram = std::max(peak_ram, input.ram_used);\n      peak_swap = std::max(peak_swap, input.swap_used);\n    }\n    // Average FPS\n    result = 1000 / (total / sorted.size());\n    out << fixed << setprecision(1) << result << \",\";\n    // GPU Load (Average)\n    result = total_gpu / sorted.size();\n    out << result << \",\";\n    // CPU Load (Average)\n    result = total_cpu / sorted.size();\n    out << result << \",\";\n    // Average Frame Time\n    result = total / sorted.size();\n    out << result << \",\";\n    // Average GPU Temp\n    result = total_gpu_temp / sorted.size();\n    out << result << \",\";\n    // Average CPU Temp\n    result = total_cpu_temp / sorted.size();\n    out << result << \",\";\n    // Average VRAM Used\n    result = total_vram / sorted.size();\n    out << result << \",\";\n    // Average RAM Used\n    result = total_ram / sorted.size();\n    out << result << \",\";\n    // Average Swap Used\n    result = total_swap / sorted.size();\n    out << result << \",\";\n    // Peak GPU Load\n    out << peak_gpu << \",\";\n    // Peak CPU Load\n    out << peak_cpu << \",\";\n    // Peak GPU Temp\n    out << peak_gpu_temp << \",\";\n    // Peak CPU Temp\n    out << peak_cpu_temp << \",\";\n    // Peak VRAM Used\n    out << peak_vram << \",\";\n    // Peak RAM Used\n    out << peak_ram << \",\";\n    // Peak Swap Used\n    out << peak_swap;\n  } else {\n    SPDLOG_ERROR(\"Failed to write log file\");\n  }\n  out.close();\n}\n\nstatic void writeFileHeaders(ofstream& out){\n    auto params = get_params();  \n    if (params->enabled[OVERLAY_PARAM_ENABLED_log_versioning]){\n      printf(\"log versioning\");\n      out << \"v1\" << endl;\n      out << MANGOHUD_VERSION << endl;\n      out << \"---------------------SYSTEM INFO---------------------\" << endl;\n    }\n\n    out << \"os,\" << \"cpu,\" << \"gpu,\" << \"ram,\" << \"kernel,\" << \"driver,\" << \"cpuscheduler\" << endl;\n    out << os << \",\" << cpu << \",\" << gpu << \",\" << ram << \",\" << kernel << \",\" << driver << \",\" << cpusched << endl;\n\n    if (params->enabled[OVERLAY_PARAM_ENABLED_log_versioning])\n      out << \"--------------------FRAME METRICS--------------------\" << endl;\n\n    out << \"fps,\" << \"frametime,\" << \"cpu_load,\" << \"cpu_power,\" << \"gpu_load,\"\n        << \"cpu_temp,\" << \"gpu_temp,\" << \"gpu_core_clock,\" << \"gpu_mem_clock,\"\n        << \"gpu_vram_used,\" << \"gpu_power,\" << \"ram_used,\" << \"swap_used,\"\n        << \"process_rss,\" << \"cpu_mhz,\" << \"elapsed\" << endl;\n\n}\n\nvoid Logger::writeToFile(){\n  if (!output_file){\n    output_file.open(m_log_files.back(), ios::out | ios::app);\n    writeFileHeaders(output_file);\n  }\n\n  auto& logArray = logger->get_log_data();\n  if (output_file && !logArray.empty()){\n    output_file << logArray.back().fps << \",\";\n    output_file << logArray.back().frametime << \",\";\n    output_file << logArray.back().cpu_load << \",\";\n    output_file << logArray.back().cpu_power << \",\";\n    output_file << logArray.back().gpu_load << \",\";\n    output_file << logArray.back().cpu_temp << \",\";\n    output_file << logArray.back().gpu_temp << \",\";\n    output_file << logArray.back().gpu_core_clock << \",\";\n    output_file << logArray.back().gpu_mem_clock << \",\";\n    output_file << logArray.back().gpu_vram_used << \",\";\n    output_file << logArray.back().gpu_power << \",\";\n    output_file << logArray.back().ram_used << \",\";\n    output_file << logArray.back().swap_used << \",\";\n    output_file << logArray.back().process_rss << \",\";\n    output_file << logArray.back().cpu_mhz << \",\";\n    output_file << std::chrono::duration_cast<std::chrono::nanoseconds>(logArray.back().previous).count() << \"\\n\";\n    output_file.flush();\n  } else {\n    printf(\"MANGOHUD: Failed to write log file\\n\");\n  }\n}\n\nstatic string get_log_suffix(){\n  time_t now_log = time(0);\n  tm *log_time = localtime(&now_log);\n  std::ostringstream buffer;\n  buffer << std::put_time(log_time, \"%Y-%m-%d_%H-%M-%S\") << \".csv\";\n  string log_name = buffer.str();\n  return log_name;\n}\n\nLogger::Logger(const overlay_params* in_params)\n  : output_folder(in_params->output_folder),\n\tlog_interval(in_params->log_interval),\n\tlog_duration(in_params->log_duration),\n    m_logging_on(false),\n    m_values_valid(false)\n{\n  if(output_folder.empty()) output_folder = std::getenv(\"HOME\");\n  m_log_end = Clock::now() - 15s;\n  SPDLOG_DEBUG(\"Logger constructed!\");\n}\n\nvoid Logger::start_logging() {\n  if(m_logging_on) return;\n  m_values_valid = false;\n  m_logging_on = true;\n  m_log_start = Clock::now();\n\n  std::string program = get_wine_exe_name();\n\n  if (program.empty())\n      program = get_program_name();\n\n  m_log_files.emplace_back(output_folder + \"/\" + program + \"_\" + get_log_suffix());\n\n  if(log_interval != 0){\n    std::thread log_thread(&Logger::logging, this);\n    // \"mangohud-logging\" wouldn't fit in the 15 byte limit\n    pthread_setname_np(log_thread.native_handle(), \"mangohud-log\");\n    log_thread.detach();\n  }\n}\n\nvoid Logger::stop_logging() {\n  if(!m_logging_on) return;\n  m_logging_on = false;\n  m_log_end = Clock::now();\n  if (log_thread.joinable()) log_thread.join();\n\n  calculate_benchmark_data();\n  try {\n      if (output_file.is_open()) {\n          output_file.close();\n      }\n  } catch (...) {\n    SPDLOG_INFO(\"Something went wrong when closing output_file\");\n  }\n\n  if (!m_log_files.empty())\n    writeSummary(m_log_files.back());\n  else\n    SPDLOG_INFO(\"Can't write summary because m_log_files is empty\");\n\n  clear_log_data();\n#ifdef __linux__\n  control_client_check(get_params()->control, global_control_client, gpu.c_str());\n  const char * cmd = \"LoggingFinished\";\n  control_send(global_control_client, cmd, strlen(cmd), 0, 0);\n#endif\n}\n\nvoid Logger::logging(){\n  wait_until_data_valid();\n  while (is_active()){\n      try_log();\n      this_thread::sleep_for(std::chrono::milliseconds(log_interval));\n  }\n  clear_log_data();\n}\n\nvoid Logger::try_log() {\n  if(!is_active()) return;\n  if(!m_values_valid) return;\n  auto now = Clock::now();\n  auto elapsedLog = now - m_log_start;\n\n  currentLogData.previous = elapsedLog;\n  currentLogData.fps = fps;\n  currentLogData.frametime = frametime;\n  m_log_array.push_back(currentLogData);\n  writeToFile();\n\n  if(log_duration && (elapsedLog >= std::chrono::seconds(log_duration))){\n    stop_logging();\n  }\n}\n\nvoid Logger::wait_until_data_valid() {\n  std::unique_lock<std::mutex> lck(m_values_valid_mtx);\n  while(! m_values_valid) m_values_valid_cv.wait(lck);\n}\n\nvoid Logger::notify_data_valid() {\n  std::unique_lock<std::mutex> lck(m_values_valid_mtx);\n  m_values_valid = true;\n  m_values_valid_cv.notify_all();\n}\n\nvoid Logger::upload_last_log() {\n  if(m_log_files.empty()) return;\n  std::thread(upload_file, m_log_files.back()).detach();\n}\n\nvoid Logger::upload_last_logs() {\n  if(m_log_files.empty()) return;\n  std::thread(upload_files, m_log_files).detach();\n}\n\nvoid autostart_log(int sleep) {\n  // os_time_sleep() causes freezes with zink + autologging :frog_donut:\n  this_thread::sleep_for(chrono::seconds(sleep));\n  logger->start_logging();\n}\n\nvoid Logger::calculate_benchmark_data(){\n  vector<float> fps_values {};\n  for (auto& point : m_log_array)\n    fps_values.push_back(point.frametime);\n\n  benchmark.percentile_data.clear();\n\n  std::vector<std::string> metrics {\"0.97\", \"avg\", \"0.01\", \"0.001\"};\n  std::unique_ptr<fpsMetrics> fpsmetrics;\n  auto params = get_params();\n  if (!params->fps_metrics.empty())\n    metrics = params->fps_metrics;\n    \n  fpsmetrics = std::make_unique<fpsMetrics>(metrics, fps_values);\n  auto metrics_copy = fpsmetrics->copy_metrics();\n  for (auto& metric : metrics_copy)\n    benchmark.percentile_data.push_back({metric.display_name, metric.value});\n\n  fpsmetrics.reset();\n}\n"
  },
  {
    "path": "src/logging.h",
    "content": "#pragma once\n#ifndef MANGOHUD_LOGGING_H\n#define MANGOHUD_LOGGING_H\n\n#include <iostream>\n#include <vector>\n#include <fstream>\n#include <chrono>\n#include <thread>\n#include <condition_variable>\n\n#include \"timing.hpp\"\n\n#include \"overlay_params.h\"\n\nstruct logData{\n  double fps;\n  float frametime;\n  float cpu_load;\n  float cpu_power;\n  int cpu_mhz;\n  int gpu_load;\n  int cpu_temp;\n  int gpu_temp;\n  int gpu_core_clock;\n  int gpu_mem_clock;\n  int gpu_power;\n  float gpu_vram_used;\n  float ram_used;\n  float swap_used;\n  float process_rss;\n\n  Clock::duration previous;\n};\n\nclass Logger {\npublic:\n  Logger(const overlay_params* in_params);\n\n  void start_logging();\n  void stop_logging();\n  void logging();\n\n  void try_log();\n\n  bool is_active() const { return m_logging_on; }\n\n  void wait_until_data_valid();\n  void notify_data_valid();\n\n  auto last_log_end() const noexcept { return m_log_end; }\n  auto last_log_begin() const noexcept { return m_log_start; }\n\n  const std::vector<logData>& get_log_data() const noexcept { return m_log_array; }\n  void clear_log_data() noexcept { m_log_array.clear(); }\n\n  void writeToFile();\n\n  void upload_last_log();\n  void upload_last_logs();\n  void calculate_benchmark_data();\n  std::string output_folder;\n  const int64_t log_interval;\n  const int64_t log_duration;\n  bool autostart_init = false;\n\nprivate:\n  std::vector<logData> m_log_array;\n  std::vector<std::string> m_log_files;\n  Clock::time_point m_log_start;\n  Clock::time_point m_log_end;\n  bool m_logging_on;\n\n  std::mutex m_values_valid_mtx;\n  std::condition_variable m_values_valid_cv;\n  bool m_values_valid;\n};\n\nextern std::shared_ptr<Logger> logger;\n\nextern std::string os, cpu, gpu, ram, kernel, driver, cpusched;\nextern bool sysInfoFetched;\nextern double fps;\nextern float frametime;\nextern logData currentLogData;\n\nstd::string exec(std::string command);\nvoid autostart_log(int sleep);\n\n#endif //MANGOHUD_LOGGING_H\n"
  },
  {
    "path": "src/mangohud.json.in",
    "content": "{\n    \"file_format_version\" : \"1.0.0\",\n    \"layer\" : {\n      \"name\": \"VK_LAYER_MANGOHUD_overlay_@cpu_family@\",\n      \"type\": \"GLOBAL\",\n      \"api_version\": \"1.3.0\",\n      \"library_path\": \"@ld_libdir_mangohud_abs@/libMangoHud.so\",\n      \"implementation_version\": \"1\",\n      \"description\": \"Vulkan Hud Overlay\",\n      \"functions\": {\n         \"vkGetInstanceProcAddr\": \"overlay_GetInstanceProcAddr\",\n         \"vkGetDeviceProcAddr\": \"overlay_GetDeviceProcAddr\"\n      },\n      \"enable_environment\": {\n        \"MANGOHUD\": \"1\"\n      },\n      \"disable_environment\": {\n        \"DISABLE_MANGOHUD\": \"1\"\n      }\n    }\n}\n"
  },
  {
    "path": "src/mangohud.version",
    "content": "# in base\n{\n  global:\n    overlay_GetInstanceProcAddr;\n    overlay_GetDeviceProcAddr;\n    glX*;\n    egl*;\n    dlsym;\n    mangohud_find_glx_ptr;\n    mangohud_find_egl_ptr;\n  local: *;\n};\n"
  },
  {
    "path": "src/memory.cpp",
    "content": "#include <array>\n#include <fstream>\n#include <map>\n#include <spdlog/spdlog.h>\n#include <string>\n#include <unistd.h>\n#include <vector>\n\n#include \"memory.h\"\n#include \"file_utils.h\"\n#include \"hud_elements.h\"\n\nfloat memused, memmax, swapused;\nint mem_temp;\nuint64_t proc_mem_resident, proc_mem_shared, proc_mem_virt;\n\nvoid update_meminfo() {\n    std::ifstream file(\"/proc/meminfo\");\n    std::map<std::string, float> meminfo;\n\n    if (!file.is_open()) {\n        SPDLOG_ERROR(\"can't open /proc/meminfo\");\n        return;\n    }\n\n    for (std::string line; std::getline(file, line);) {\n        auto key = line.substr(0, line.find(\":\"));\n        auto val = line.substr(key.length() + 2);\n        meminfo[key] = std::stoull(val) / 1024.f / 1024.f;\n    }\n\n    memmax = meminfo[\"MemTotal\"];\n    memused = meminfo[\"MemTotal\"] - meminfo[\"MemAvailable\"];\n    swapused = meminfo[\"SwapTotal\"] - meminfo[\"SwapFree\"];\n}\n\nvoid update_mem_temp() {\n    static bool inited = false;\n    static std::vector<std::ifstream> mem_temp_files;\n\n    if (!inited) {\n        inited = true;\n        std::string path = \"/sys/class/hwmon/\";\n        auto dirs = ls(path.c_str(), \"hwmon\", LS_DIRS);\n        for (auto &dir : dirs) {\n            if (read_line(path + dir + \"/name\") == \"spd5118\")\n                mem_temp_files.emplace_back(path + dir + \"/temp1_input\");\n        }\n        if (mem_temp_files.empty())\n            SPDLOG_ERROR(\"failed to find known ram temp sensors\");\n    }\n\n    int temp = 0;\n    for (auto &file : mem_temp_files) {\n        int _temp;\n        file.clear();\n        file.seekg(0);\n        if ((file >> _temp) && _temp > temp)\n            temp = _temp;\n    }\n    mem_temp = temp / 1000;\n}\n\nvoid update_procmem()\n{\n    auto page_size = sysconf(_SC_PAGESIZE);\n    if (page_size < 0) page_size = 4096;\n\n    std::string f = \"/proc/\";\n\n    {\n        auto gs_pid = HUDElements.g_gamescopePid;\n        f += gs_pid < 1 ? \"self\" : std::to_string(gs_pid);\n        f += \"/statm\";\n    }\n\n    std::ifstream file(f);\n\n    if (!file.is_open()) {\n        SPDLOG_ERROR(\"can't open {}\", f);\n        return;\n    }\n\n    size_t last_idx = 0;\n    std::string line;\n    std::getline(file, line);\n\n    if (line.empty())\n        return;\n\n    std::array<uint64_t, 3> meminfo;\n\n    for (auto i = 0; i < 3; i++) {\n        auto idx = line.find(\" \", last_idx);\n        auto val = line.substr(last_idx, idx);\n\n        meminfo[i] = std::stoull(val) * page_size;\n        last_idx = idx + 1;\n    }\n\n    proc_mem_virt = meminfo[0];\n    proc_mem_resident = meminfo[1];\n    proc_mem_shared = meminfo[2];\n}\n"
  },
  {
    "path": "src/memory.h",
    "content": "#pragma once\n#ifndef MANGOHUD_MEMORY_H\n#define MANGOHUD_MEMORY_H\n\n#include <cstdint>\n\nextern float memused, memmax, swapused;\nextern int mem_temp;\nextern uint64_t proc_mem_resident, proc_mem_shared, proc_mem_virt;\n\nvoid update_meminfo();\nvoid update_mem_temp();\nvoid update_procmem();\n\n#endif //MANGOHUD_MEMORY_H\n"
  },
  {
    "path": "src/mesa/c11_compat.h",
    "content": "/* Copyright 2019 Intel Corporation */\n/* SPDX-License-Identifier: MIT */\n\n#include \"no_extern_c.h\"\n\n#ifndef _C11_COMPAT_H_\n#define _C11_COMPAT_H_\n\n#if defined(__cplusplus)\n   /* This is C++ code, not C */\n#elif (__STDC_VERSION__ >= 201112L)\n   /* Already C11 */\n#else\n\n\n/*\n * C11 static_assert() macro\n * assert.h only defines that name for C11 and above\n */\n#ifndef static_assert\n#define static_assert _Static_assert\n#endif\n\n\n#endif /* !C++ && !C11 */\n\n#endif /* _C11_COMPAT_H_ */\n"
  },
  {
    "path": "src/mesa/c99_compat.h",
    "content": "/**************************************************************************\n *\n * Copyright 2007-2013 VMware, Inc.\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * 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, sub license, 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 (including the\n * next paragraph) shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n * ANY 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 **************************************************************************/\n\n#include \"no_extern_c.h\"\n\n#ifndef _C99_COMPAT_H_\n#define _C99_COMPAT_H_\n\n\n/*\n * MSVC hacks.\n */\n#if defined(_MSC_VER)\n\n#  if _MSC_VER < 1900\n#    error \"Microsoft Visual Studio 2015 or higher required\"\n#  endif\n\n   /*\n    * Visual Studio will complain if we define the `inline` keyword, but\n    * actually it only supports the keyword on C++.\n    *\n    * To avoid this the _ALLOW_KEYWORD_MACROS must be set.\n    */\n#  if !defined(_ALLOW_KEYWORD_MACROS)\n#    define _ALLOW_KEYWORD_MACROS\n#  endif\n\n   /*\n    * XXX: MSVC has a `__restrict` keyword, but it also has a\n    * `__declspec(restrict)` modifier, so it is impossible to define a\n    * `restrict` macro without interfering with the latter.  Furthermore the\n    * MSVC standard library uses __declspec(restrict) under the _CRTRESTRICT\n    * macro.  For now resolve this issue by redefining _CRTRESTRICT, but going\n    * forward we should probably should stop using restrict, especially\n    * considering that our code does not obbey strict aliasing rules any way.\n    */\n#  include <crtdefs.h>\n#  undef _CRTRESTRICT\n#  define _CRTRESTRICT\n#endif\n\n\n/*\n * C99 inline keyword\n */\n#ifndef inline\n#  ifdef __cplusplus\n     /* C++ supports inline keyword */\n#  elif defined(__GNUC__)\n#    define inline __inline__\n#  elif defined(_MSC_VER)\n#    define inline __inline\n#  elif defined(__ICL)\n#    define inline __inline\n#  elif defined(__INTEL_COMPILER)\n     /* Intel compiler supports inline keyword */\n#  elif defined(__WATCOMC__) && (__WATCOMC__ >= 1100)\n#    define inline __inline\n#  elif (__STDC_VERSION__ >= 199901L)\n     /* C99 supports inline keyword */\n#  else\n#    define inline\n#  endif\n#endif\n\n\n/*\n * C99 restrict keyword\n *\n * See also:\n * - http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html\n */\n#ifndef restrict\n#  if (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)\n     /* C99 */\n#  elif defined(__GNUC__)\n#    define restrict __restrict__\n#  elif defined(_MSC_VER)\n#    define restrict __restrict\n#  else\n#    define restrict /* */\n#  endif\n#endif\n\n\n/*\n * C99 __func__ macro\n */\n#ifndef __func__\n#  if (__STDC_VERSION__ >= 199901L)\n     /* C99 */\n#  elif defined(__GNUC__)\n#    define __func__ __FUNCTION__\n#  elif defined(_MSC_VER)\n#    define __func__ __FUNCTION__\n#  else\n#    define __func__ \"<unknown>\"\n#  endif\n#endif\n\n\n/* Simple test case for debugging */\n#if 0\nstatic inline const char *\ntest_c99_compat_h(const void * restrict a,\n                  const void * restrict b)\n{\n   return __func__;\n}\n#endif\n\n\n/* Fallback definitions, for scons which doesn't auto-detect these things. */\n#ifdef HAVE_SCONS\n\n#  ifndef _WIN32\n#    define HAVE_PTHREAD\n#    define HAVE_POSIX_MEMALIGN\n#  endif\n\n#  ifdef __GNUC__\n#    if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)\n#      error \"GCC version 4.2 or higher required\"\n#    endif\n\n     /* https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Other-Builtins.html */\n#    define HAVE___BUILTIN_CLZ 1\n#    define HAVE___BUILTIN_CLZLL 1\n#    define HAVE___BUILTIN_CTZ 1\n#    define HAVE___BUILTIN_EXPECT 1\n#    define HAVE___BUILTIN_FFS 1\n#    define HAVE___BUILTIN_FFSLL 1\n#    define HAVE___BUILTIN_POPCOUNT 1\n#    define HAVE___BUILTIN_POPCOUNTLL 1\n     /* https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Function-Attributes.html */\n#    define HAVE_FUNC_ATTRIBUTE_FLATTEN 1\n#    define HAVE_FUNC_ATTRIBUTE_UNUSED 1\n#    define HAVE_FUNC_ATTRIBUTE_FORMAT 1\n#    define HAVE_FUNC_ATTRIBUTE_PACKED 1\n#    define HAVE_FUNC_ATTRIBUTE_ALIAS 1\n#    define HAVE_FUNC_ATTRIBUTE_NORETURN 1\n\n#    if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)\n       /* https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gcc/Other-Builtins.html */\n#      define HAVE___BUILTIN_BSWAP32 1\n#      define HAVE___BUILTIN_BSWAP64 1\n#    endif\n\n#    if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)\n#      define HAVE___BUILTIN_UNREACHABLE 1\n#    endif\n\n#  endif /* __GNUC__ */\n\n#endif /* HAVE_SCONS */\n\n\n#endif /* _C99_COMPAT_H_ */\n"
  },
  {
    "path": "src/mesa/no_extern_c.h",
    "content": "/**************************************************************************\n *\n * Copyright 2014 VMware, Inc.\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to 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 Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n **************************************************************************/\n\n\n/*\n * Including system's headers inside `extern \"C\" { ... }` is not safe, as system\n * headers may have C++ code in them, and C++ code inside extern \"C\"\n * leads to syntatically incorrect code.\n *\n * This is because putting code inside extern \"C\" won't make __cplusplus define\n * go away, that is, the system header being included thinks is free to use C++\n * as it sees fits.\n *\n * Including non-system headers inside extern \"C\"  is not safe either, because\n * non-system headers end up including system headers, hence fall in the above\n * case too.\n *\n * Conclusion, includes inside extern \"C\" is simply not portable.\n *\n *\n * This header helps surface these issues.\n */\n\n#ifdef __cplusplus\ntemplate<class T> class _IncludeInsideExternCNotPortable;\n#endif\n"
  },
  {
    "path": "src/mesa/util/detect_os.h",
    "content": "/* SPDX-License-Identifier: MIT */\n/* Copyright 2008 VMware, Inc. */\n\n/**\n * Auto-detect the operating system family.\n *\n * See also:\n * - http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html\n * - echo | gcc -dM -E - | sort\n * - http://msdn.microsoft.com/en-us/library/b0084kay.aspx\n *\n * @author José Fonseca <jfonseca@vmware.com>\n */\n\n#ifndef DETECT_OS_H\n#define DETECT_OS_H\n\n#if defined(__linux__)\n#define DETECT_OS_LINUX 1\n#define DETECT_OS_UNIX 1\n#endif\n\n/*\n * Android defines __linux__, so DETECT_OS_LINUX and DETECT_OS_UNIX will\n * also be defined.\n */\n#if defined(ANDROID)\n#define DETECT_OS_ANDROID 1\n#endif\n\n#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)\n#define DETECT_OS_FREEBSD 1\n#define DETECT_OS_BSD 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__OpenBSD__)\n#define DETECT_OS_OPENBSD 1\n#define DETECT_OS_BSD 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__NetBSD__)\n#define DETECT_OS_NETBSD 1\n#define DETECT_OS_BSD 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__DragonFly__)\n#define DETECT_OS_DRAGONFLY 1\n#define DETECT_OS_BSD 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__GNU__)\n#define DETECT_OS_HURD 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__sun)\n#define DETECT_OS_SOLARIS 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__APPLE__)\n#define DETECT_OS_APPLE 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(_WIN32) || defined(WIN32)\n#define DETECT_OS_WINDOWS 1\n#endif\n\n#if defined(__HAIKU__)\n#define DETECT_OS_HAIKU 1\n#define DETECT_OS_UNIX 1\n#endif\n\n#if defined(__CYGWIN__)\n#define DETECT_OS_CYGWIN 1\n#define DETECT_OS_UNIX 1\n#endif\n\n\n/*\n * Make sure DETECT_OS_* are always defined, so that they can be used with #if\n */\n#ifndef DETECT_OS_ANDROID\n#define DETECT_OS_ANDROID 0\n#endif\n#ifndef DETECT_OS_APPLE\n#define DETECT_OS_APPLE 0\n#endif\n#ifndef DETECT_OS_BSD\n#define DETECT_OS_BSD 0\n#endif\n#ifndef DETECT_OS_CYGWIN\n#define DETECT_OS_CYGWIN 0\n#endif\n#ifndef DETECT_OS_DRAGONFLY\n#define DETECT_OS_DRAGONFLY 0\n#endif\n#ifndef DETECT_OS_FREEBSD\n#define DETECT_OS_FREEBSD 0\n#endif\n#ifndef DETECT_OS_HAIKU\n#define DETECT_OS_HAIKU 0\n#endif\n#ifndef DETECT_OS_HURD\n#define DETECT_OS_HURD 0\n#endif\n#ifndef DETECT_OS_LINUX\n#define DETECT_OS_LINUX 0\n#endif\n#ifndef DETECT_OS_NETBSD\n#define DETECT_OS_NETBSD 0\n#endif\n#ifndef DETECT_OS_OPENBSD\n#define DETECT_OS_OPENBSD 0\n#endif\n#ifndef DETECT_OS_SOLARIS\n#define DETECT_OS_SOLARIS 0\n#endif\n#ifndef DETECT_OS_UNIX\n#define DETECT_OS_UNIX 0\n#endif\n#ifndef DETECT_OS_WINDOWS\n#define DETECT_OS_WINDOWS 0\n#endif\n\n#endif /* DETECT_OS_H */\n"
  },
  {
    "path": "src/mesa/util/macros.h",
    "content": "// /*\n//  * Copyright © 2014 Intel Corporation\n//  *\n//  * Permission is hereby granted, free of charge, to any person obtaining a\n//  * copy of this software and associated documentation files (the \"Software\"),\n//  * to deal in the Software without restriction, including without limitation\n//  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n//  * and/or sell copies of the Software, and to permit persons to whom the\n//  * Software is furnished to do so, subject to the following conditions:\n//  *\n//  * The above copyright notice and this permission notice (including the next\n//  * paragraph) shall be included in all copies or substantial portions of the\n//  * 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,\n//  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n//  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n//  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n//  * IN THE SOFTWARE.\n//  */\n\n#ifndef UTIL_MACROS_H\n#define UTIL_MACROS_H\n\n#include <assert.h>\n#include \"../c99_compat.h\"\n#include \"../c11_compat.h\"\n#if defined(__HAIKU__)  && !defined(__cplusplus)\n#define static_assert _Static_assert\n#endif\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n// /* Compute the size of an array */\n#ifndef ARRAY_SIZE\n#  define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))\n#endif\n#if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable)\n#define UNREACHABLE(str)    \\\ndo {                        \\\n   (void)\"\" str; /* str must be a string literal */ \\\n   assert(!str);            \\\n   __builtin_unreachable(); \\\n} while (0)\n#elif defined (_MSC_VER)\n#define UNREACHABLE(str)    \\\ndo {                        \\\n   (void)\"\" str; /* str must be a string literal */ \\\n   assert(!str);            \\\n   __assume(0);             \\\n} while (0)\n#else\n#define UNREACHABLE(str)    \\\ndo {                        \\\n   (void)\"\" str; /* str must be a string literal */ \\\n   assert(!str);            \\\n} while (0)\n#endif\n\n#define PUBLIC __attribute__((visibility(\"default\")))\n#endif /* UTIL_MACROS_H */\n"
  },
  {
    "path": "src/mesa/util/os_socket.c",
    "content": "/*\n * Copyright 2019 Intel Corporation\n * SPDX-License-Identifier: MIT\n */\n\n#include <errno.h>\n\n#include \"os_socket.h\"\n\n#if defined(__linux__)\n\n#include <fcntl.h>\n#include <poll.h>\n#include <stddef.h>\n#include <string.h>\n#include <sys/socket.h>\n#include <sys/un.h>\n#include <unistd.h>\n\nint\nos_socket_listen_abstract(const char *path, int count)\n{\n   int s = socket(AF_UNIX, SOCK_STREAM, 0);\n   if (s < 0)\n      return -1;\n\n   struct sockaddr_un addr;\n   memset(&addr, 0, sizeof(addr));\n   addr.sun_family = AF_UNIX;\n   strncpy(addr.sun_path + 1, path, sizeof(addr.sun_path) - 2);\n\n   /* Create an abstract socket */\n   int ret = bind(s, (struct sockaddr*)&addr,\n                  offsetof(struct sockaddr_un, sun_path) +\n                  strlen(path) + 1);\n   if (ret < 0)\n      return -1;\n\n   listen(s, count);\n\n   return s;\n}\n\nint\nos_socket_accept(int s)\n{\n   return accept(s, NULL, NULL);\n}\n\nssize_t\nos_socket_recv(int socket, void *buffer, size_t length, int flags)\n{\n   return recv(socket, buffer, length, flags);\n}\n\nssize_t\nos_socket_send(int socket, const void *buffer, size_t length, int flags)\n{\n   return send(socket, buffer, length, flags);\n}\n\nvoid\nos_socket_block(int s, bool block)\n{\n   int old = fcntl(s, F_GETFL, 0);\n   if (old == -1)\n      return;\n\n   /* TODO obey block */\n   if (block)\n      fcntl(s, F_SETFL, old & ~O_NONBLOCK);\n   else\n      fcntl(s, F_SETFL, old | O_NONBLOCK);\n}\n\nvoid\nos_socket_close(int s)\n{\n   close(s);\n}\n\n#else\n\nint\nos_socket_listen_abstract(const char *path, int count)\n{\n   errno = -ENOSYS;\n   return -1;\n}\n\nint\nos_socket_accept(int s)\n{\n   errno = -ENOSYS;\n   return -1;\n}\n\nssize_t\nos_socket_recv(int socket, void *buffer, size_t length, int flags)\n{\n   errno = -ENOSYS;\n   return -1;\n}\n\nssize_t\nos_socket_send(int socket, const void *buffer, size_t length, int flags)\n{\n   errno = -ENOSYS;\n   return -1;\n}\n\nvoid\nos_socket_block(int s, bool block)\n{\n}\n\nvoid\nos_socket_close(int s)\n{\n}\n\n#endif\n"
  },
  {
    "path": "src/mesa/util/os_socket.h",
    "content": "/*\n * Copyright 2019 Intel Corporation\n * SPDX-License-Identifier: MIT\n *\n * Socket operations helpers\n */\n\n#ifndef _OS_SOCKET_H_\n#define _OS_SOCKET_H_\n\n#include <stdio.h>\n#include <stdbool.h>\n#ifdef _MSC_VER\n#include <BaseTsd.h>\ntypedef SSIZE_T ssize_t;\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nint os_socket_accept(int s);\n\nint os_socket_listen_abstract(const char *path, int count);\n\nssize_t os_socket_recv(int socket, void *buffer, size_t length, int flags);\nssize_t os_socket_send(int socket, const void *buffer, size_t length, int flags);\n\nvoid os_socket_block(int s, bool block);\nvoid os_socket_close(int s);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _OS_SOCKET_H_ */\n"
  },
  {
    "path": "src/mesa/util/os_time.c",
    "content": "/**************************************************************************\n *\n * Copyright 2008-2010 VMware, Inc.\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * 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, sub license, 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 (including the\n * next paragraph) shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n * ANY 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 **************************************************************************/\n\n/**\n * @file\n * OS independent time-manipulation functions.\n *\n * @author Jose Fonseca <jfonseca@vmware.com>\n */\n\n#include \"os_time.h\"\n#include \"detect_os.h\"\n\n#if defined(USE_GCC_ATOMIC_BUILTINS)\n/* The builtins with explicit memory model are available since GCC 4.7. */\n#define p_atomic_read(_v) __atomic_load_n((_v), __ATOMIC_ACQUIRE)\n#else\n#define p_atomic_read(_v) (*(_v))\n#endif\n\n#if DETECT_OS_UNIX\n#  include <unistd.h> /* usleep */\n#  include <time.h> /* timeval */\n#  include <sys/time.h> /* timeval */\n#  include <sched.h> /* sched_yield */\n#  include <errno.h>\n#elif DETECT_OS_WINDOWS\n#  include <windows.h>\n#else\n#  error Unsupported OS\n#endif\n\n#if defined(CLOCK_MONOTONIC_RAW) /* linux */\n#define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC_RAW\n#elif defined(CLOCK_MONOTONIC_FAST) /* freebsd */\n#define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC_FAST\n#else /* fallback */\n#define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC\n#endif\n\nint64_t\nos_time_get_nano(void)\n{\n#if DETECT_OS_LINUX || DETECT_OS_BSD\n\n   struct timespec tv;\n   clock_gettime(MANGOHUD_CLOCKTYPE, &tv);\n   return tv.tv_nsec + tv.tv_sec*INT64_C(1000000000);\n\n#elif DETECT_OS_UNIX\n\n   struct timeval tv;\n   gettimeofday(&tv, NULL);\n   return tv.tv_usec*INT64_C(1000) + tv.tv_sec*INT64_C(1000000000);\n\n#elif DETECT_OS_WINDOWS\n\n   static LARGE_INTEGER frequency;\n   LARGE_INTEGER counter;\n   int64_t secs, nanosecs;\n   if(!frequency.QuadPart)\n      QueryPerformanceFrequency(&frequency);\n   QueryPerformanceCounter(&counter);\n   /* Compute seconds and nanoseconds parts separately to\n    * reduce severity of precision loss.\n    */\n   secs = counter.QuadPart / frequency.QuadPart;\n   nanosecs = (counter.QuadPart % frequency.QuadPart) * INT64_C(1000000000)\n      / frequency.QuadPart;\n   return secs*INT64_C(1000000000) + nanosecs;\n\n#else\n\n#error Unsupported OS\n\n#endif\n}\n\n\n\nvoid\nos_time_sleep(int64_t usecs)\n{\n#if DETECT_OS_LINUX\n   struct timespec time;\n   time.tv_sec = usecs / 1000000;\n   time.tv_nsec = (usecs % 1000000) * 1000;\n   while (clock_nanosleep(MANGOHUD_CLOCKTYPE, 0, &time, &time) == EINTR);\n\n#elif DETECT_OS_UNIX\n   usleep(usecs);\n\n#elif DETECT_OS_WINDOWS\n   DWORD dwMilliseconds = (DWORD) ((usecs + 999) / 1000);\n   /* Avoid Sleep(O) as that would cause to sleep for an undetermined duration */\n   if (dwMilliseconds) {\n      Sleep(dwMilliseconds);\n   }\n#else\n#  error Unsupported OS\n#endif\n}\n\n\n\nint64_t\nos_time_get_absolute_timeout(uint64_t timeout)\n{\n   int64_t time, abs_timeout;\n\n   /* Also check for the type upper bound. */\n   if (timeout == OS_TIMEOUT_INFINITE || timeout > INT64_MAX)\n      return OS_TIMEOUT_INFINITE;\n\n   time = os_time_get_nano();\n   abs_timeout = time + (int64_t)timeout;\n\n   /* Check for overflow. */\n   if (abs_timeout < time)\n      return OS_TIMEOUT_INFINITE;\n\n   return abs_timeout;\n}\n\n\nbool\nos_wait_until_zero(volatile int *var, uint64_t timeout)\n{\n   if (!p_atomic_read(var))\n      return true;\n\n   if (!timeout)\n      return false;\n\n   if (timeout == OS_TIMEOUT_INFINITE) {\n      while (p_atomic_read(var)) {\n#if DETECT_OS_UNIX\n         sched_yield();\n#endif\n      }\n      return true;\n   }\n   else {\n      int64_t start_time = os_time_get_nano();\n      int64_t end_time = start_time + timeout;\n\n      while (p_atomic_read(var)) {\n         if (os_time_timeout(start_time, end_time, os_time_get_nano()))\n            return false;\n\n#if DETECT_OS_UNIX\n         sched_yield();\n#endif\n      }\n      return true;\n   }\n}\n\n\nbool\nos_wait_until_zero_abs_timeout(volatile int *var, int64_t timeout)\n{\n   if (!p_atomic_read(var))\n      return true;\n\n   if (timeout == (int64_t)OS_TIMEOUT_INFINITE)\n      return os_wait_until_zero(var, OS_TIMEOUT_INFINITE);\n\n   while (p_atomic_read(var)) {\n      if (os_time_get_nano() >= timeout)\n         return false;\n\n#if DETECT_OS_UNIX\n      sched_yield();\n#endif\n   }\n   return true;\n}\n"
  },
  {
    "path": "src/mesa/util/os_time.h",
    "content": "/**************************************************************************\n *\n * Copyright 2008-2010 VMware, Inc.\n * All Rights Reserved.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * 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, sub license, 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 (including the\n * next paragraph) shall be included in all copies or substantial portions\n * of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\n * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR\n * ANY 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 **************************************************************************/\n\n/**\n * @file\n * OS independent time-manipulation functions.\n * \n * @author Jose Fonseca <jfonseca@vmware.com>\n */\n\n#ifndef _OS_TIME_H_\n#define _OS_TIME_H_\n\n#include <stdbool.h>\n#include <stdint.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* must be equal to PIPE_TIMEOUT_INFINITE */\n#define OS_TIMEOUT_INFINITE 0xffffffffffffffffull\n\n/*\n * Get the current time in nanoseconds from an unknown base.\n */\nint64_t\nos_time_get_nano(void);\n\n\n/*\n * Sleep.\n */\nvoid\nos_time_sleep(int64_t usecs);\n\n\n/*\n * Helper function for detecting time outs, taking in account overflow.\n *\n * Returns true if the current time has elapsed beyond the specified interval.\n */\nstatic inline bool\nos_time_timeout(int64_t start,\n                int64_t end,\n                int64_t curr)\n{\n   if (start <= end)\n      return !(start <= curr && curr < end);\n   else\n      return !((start <= curr) || (curr < end));\n}\n\n\n/**\n * Convert a relative timeout in nanoseconds into an absolute timeout,\n * in other words, it returns current time + timeout.\n * os_time_get_nano() must be monotonic.\n * OS_TIMEOUT_INFINITE is passed through unchanged. If the calculation\n * overflows, OS_TIMEOUT_INFINITE is returned.\n */\nint64_t\nos_time_get_absolute_timeout(uint64_t timeout);\n\n\n/**\n * Wait until the variable at the given memory location is zero.\n *\n * \\param var           variable\n * \\param timeout       timeout in ns, can be anything from 0 (no wait) to\n *                      OS_TIMEOUT_INFINITE (wait forever)\n * \\return     true if the variable is zero\n */\nbool\nos_wait_until_zero(volatile int *var, uint64_t timeout);\n\n\n/**\n * Wait until the variable at the given memory location is zero.\n * The timeout is the absolute time when the waiting should stop. If it is\n * less than or equal to the current time, it only returns the status and\n * doesn't wait. OS_TIMEOUT_INFINITE waits forever. This requires that\n * os_time_get_nano is monotonic.\n *\n * \\param var       variable\n * \\param timeout   the time in ns when the waiting should stop\n * \\return     true if the variable is zero\n */\nbool\nos_wait_until_zero_abs_timeout(volatile int *var, int64_t timeout);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _OS_TIME_H_ */\n"
  },
  {
    "path": "src/meson.build",
    "content": "glslang = find_program('glslang', 'glslangValidator')\n\nif get_option('dynamic_string_tokens')\n  ld_prefix = get_option('prefix') + '/\\$LIB/'\nelse\n  ld_prefix = join_paths(get_option('prefix') ,get_option('libdir')) + '/'\nendif\n\n# Needs prefix for configure_file()\nif get_option('append_libdir_mangohud')\n  libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'), 'mangohud')\n  ld_libdir_mangohud = ld_prefix + 'mangohud/'\nelse\n  libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'))\n  ld_libdir_mangohud = ld_prefix\nendif\n\ngit = find_program('git', required: false)\nif git.found()\n  git_describe = run_command([git, 'describe', '--tags', '--dirty=+'], check: false)\nendif\nif git.found() and git_describe.returncode() == 0\n  describe_ver = git_describe.stdout().strip()\nelse\n  describe_ver = meson.project_version()\nendif\n\nconf_data = configuration_data()\n\nconf_data.set('ld_libdir_mangohud_abs', libdir_mangohud)\nconf_data.set('ld_libdir_mangohud', ld_libdir_mangohud)\nconf_data.set('cpu_family', host_machine.cpu_family())\nconf_data.set('version', describe_ver)\n\noverlay_shaders = [\n  'overlay.frag',\n  'overlay.vert',\n]\noverlay_spv = []\nforeach s : ['overlay.frag', 'overlay.vert']\n  overlay_spv += custom_target(\n    s + '.spv.h', input : s, output : s + '.spv.h',\n    command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@'])\nendforeach\n\nutil_files = files(\n  'mesa/util/os_socket.c',\n  'mesa/util/os_time.c',\n)\n\nvklayer_files = files(\n  'hud_elements.cpp',\n  'overlay.cpp',\n  'overlay_params.cpp',\n  'font.cpp',\n  'keybinds.cpp',\n  'font_unispace.c',\n  'logging.cpp',\n  'config.cpp',\n  'gpu.cpp',\n  'blacklist.cpp',\n  'file_utils.cpp',\n  'nvidia.cpp',\n  'gpu_fdinfo.cpp',\n  'amdgpu.cpp'\n)\n\nopengl_files  = []\nif ['windows', 'mingw'].contains(host_machine.system())\n  vklayer_files += files(\n    'file_utils_win32.cpp',\n    'cpu_win32.cpp',\n    'nvapi.cpp',\n    'win/dxgi.cpp',\n    'win/main.cpp',\n    'win/kiero.cpp',\n    'win/d3d12_hook.cpp',\n    'win/d3d11_hook.cpp',\n    'win/d3d_shared.cpp',\n  )\nendif\n\nif is_unixy\n  vklayer_files += files(\n    'cpu.cpp',\n    'memory.cpp',\n    'iostats.cpp',\n    'notify.cpp',\n    'elfhacks.c',\n    'real_dlsym.c',\n    'pci_ids.cpp',\n    'battery.cpp',\n    'control.cpp',\n    'device.cpp',\n    'net.cpp',\n    'shell.cpp',\n    'ftrace.cpp',\n  )\n\n  if get_option('with_fex')\n    pre_args += '-DHAVE_FEX'\n    vklayer_files += files(\n      'fex.cpp',\n    )\n  endif\n\n  opengl_files = files(\n    'gl/glad.c',\n    'gl/gl_renderer.cpp',\n    'gl/gl_hud.cpp',\n    'gl/inject_egl.cpp',\n  )\n\n  nvml_h_found = get_option('with_nvml') == 'enabled'\n  if get_option('with_nvml') == 'system'\n    nvml_h_found = cc.has_header('nvml.h')\n    if not nvml_h_found\n      error('nvml.h was not found. Disable with \\'-Dwith_nvml=disabled\\' if gpu stats by NVML are not needed.')\n    endif\n    pre_args += '-DUSE_SYSTEM_NVML'\n  endif\n\n  if nvml_h_found\n    pre_args += '-DHAVE_NVML'\n    pre_args += '-DNVML_NO_UNVERSIONED_FUNC_DEFS'\n    vklayer_files += files(\n      'loaders/loader_nvml.cpp',\n    )\n  endif\n\n  if get_option('with_xnvctrl').enabled()\n\n    if not get_option('with_x11').enabled()\n      error('XNVCtrl also needs \\'with_x11\\'')\n    endif\n\n    xnvctrl_h_found = cc.has_header('NVCtrl/NVCtrl.h')\n    if not xnvctrl_h_found\n      error('NVCtrl.h was not found. Disable with \\'-Dwith_xnvctrl=disabled\\' if gpu stats by XNVCtrl are not needed.')\n    endif\n\n    pre_args += '-DHAVE_XNVCTRL'\n    vklayer_files += files(\n      'loaders/loader_nvctrl.cpp'\n    )\n  endif\n\n  if get_option('with_x11').enabled()\n    pre_args += '-DHAVE_X11'\n\n    vklayer_files += files(\n      'loaders/loader_x11.cpp',\n      'shared_x11.cpp',\n    )\n\n    opengl_files += files(\n      'loaders/loader_glx.cpp',\n      'gl/inject_glx.cpp',\n    )\n  endif\n\n  if get_option('with_wayland').enabled()\n    pre_args += '-DHAVE_WAYLAND'\n\n    vklayer_files += files(\n      'wayland_keybinds.cpp'\n    )\n  endif\n\n  if dbus_dep.found() and get_option('with_dbus').enabled()\n    pre_args += '-DHAVE_DBUS'\n    vklayer_files += files(\n      'dbus.cpp',\n      'loaders/loader_dbus.cpp',\n    )\n  endif\nendif\n\nlink_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro', '-Wl,--exclude-libs,ALL', '-lGL', '-static-libstdc++'])\n# meson fails to check version-script so just force add\nlink_args += '-Wl,--version-script,@0@'.format(join_paths(meson.current_source_dir(), 'mangohud.version'))\n\nmangohud_static_lib = static_library(\n  'MangoHud',\n  mangohud_version,\n  files('vulkan.cpp'),\n  util_files,\n  vk_enum_to_str,\n  vk_dispatch_table,\n  vk_extensions,\n  vklayer_files,\n  overlay_spv,\n  c_args : [\n    pre_args,\n    vulkan_wsi_args\n    ],\n  cpp_args : [\n    pre_args,\n    vulkan_wsi_args\n    ],\n  gnu_symbol_visibility : 'hidden',\n  dependencies : [\n    mangohud_version_dep,\n    vulkan_wsi_deps,\n    dearimgui_dep,\n    spdlog_dep,\n    dbus_dep,\n    dep_dl,\n    dep_rt,\n    dep_pthread,\n    dep_vulkan_headers,\n    dep_vulkan_utility_libraries,\n    windows_deps,\n    implot_dep],\n  include_directories : [inc_common],\n  link_args : link_args,\n  install_dir : libdir_mangohud,\n  install : false\n)\n\nmangohud_shared_lib = shared_library(\n  'MangoHud',\n  objects: mangohud_static_lib.extract_all_objects(),\n  link_with: mangohud_static_lib,\n  link_args : link_args,\n  install_dir : libdir_mangohud,\n  install: true\n)\n\nmangohud_opengl_shared_lib = shared_library(\n  'MangoHud_opengl',\n  mangohud_version,\n  opengl_files,\n  vklayer_files,\n  util_files,\n  c_args : [\n    pre_args,\n    vulkan_wsi_args\n    ],\n  cpp_args : [\n    pre_args,\n    vulkan_wsi_args\n    ],\n  dependencies : [\n    mangohud_version_dep,\n    vulkan_wsi_deps,\n    dearimgui_dep,\n    spdlog_dep,\n    dbus_dep,\n    dep_dl,\n    dep_rt,\n    dep_pthread,\n    dep_vulkan_headers,\n    dep_vulkan_utility_libraries,\n    windows_deps,\n    implot_dep],\n  include_directories : [inc_common],\n  link_args : link_args,\n  link_with: mangohud_static_lib,\n  install_dir : libdir_mangohud,\n  install: true\n)\n\nif get_option('mangoapp')\n  if not get_option('with_x11').enabled()\n    error('mangoapp also needs \\'with_x11\\'')\n  endif\n  pre_args += '-DMANGOAPP'\n  mangoapp = executable(\n    'mangoapp',\n    files(\n      'app/main.cpp',\n    ),\n    c_args : [\n      pre_args,\n      vulkan_wsi_args\n    ],\n    cpp_args : [\n      pre_args,\n      vulkan_wsi_args\n    ],\n    gnu_symbol_visibility : 'hidden',\n    dependencies : [\n      dearimgui_dep,\n      dep_dl,\n      dep_vulkan_headers,\n      dep_vulkan_utility_libraries,\n      spdlog_dep,\n      dbus_dep,\n      dep_x11,\n      dep_wayland_client,\n      glfw3_dep,\n      implot_dep\n    ],\n    include_directories : [inc_common],\n    install_tag : 'mangoapp',\n    link_with: mangohud_static_lib,\n    link_args : link_args,\n    install : true\n  )\nendif\n\nif get_option('mangohudctl')\nmangoapp = executable(\n  'mangohudctl',\n  files('app/control.c'),\n  install_tag : 'mangoapp', #TODO MangoHud layer itself currently doesn't support it\n  install : true\n)\nendif\nif is_unixy\n  mangohud_shim = shared_library(\n    'MangoHud_shim',\n    files(\n      'gl/shim.c',\n      'real_dlsym.c',\n      'elfhacks.c'\n    ),\n    dependencies : [\n      dep_dl\n    ],\n    c_args : [\n      pre_args\n    ],\n    cpp_args : [\n      pre_args\n    ],\n    include_directories : [inc_common],\n    install_dir : libdir_mangohud,\n    install: true\n  )\nendif\n\nconfigure_file(input : 'mangohud.json.in',\n  output : '@0@.@1@.json'.format(meson.project_name(), host_machine.cpu_family()),\n  configuration : conf_data,\n  install : true,\n  install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'),\n  install_tag : 'runtime',\n)\n\nconfigure_file(input : '../bin/mangohud.in',\n  output : 'mangohud',\n  configuration : conf_data,\n  install_dir : get_option('bindir'),\n  install_tag : 'scripts',\n)\n"
  },
  {
    "path": "src/net.cpp",
    "content": "#include \"net.h\"\n#include \"hud_elements.h\"\n\nNet::Net() {\n    auto params = get_params();\n    should_reset = false;\n    fs::path net_dir(NETDIR);\n    if (fs::exists(net_dir) && fs::is_directory(net_dir)) {\n        for (const auto& entry : fs::directory_iterator(net_dir)) {\n            if (fs::is_directory(entry.status())) {\n                auto val = entry.path().filename().string();\n                if (val == \"lo\")\n                    continue;\n\n                if (!params->network.empty() && params->network.front() == \"1\") {\n                    interfaces.push_back({entry.path().filename().string(), 0, 0});\n                } else if (!params->network.empty()){\n                    auto it = std::find(params->network.begin(), params->network.end(), val);\n                    if (it != params->network.end())\n                        interfaces.push_back({entry.path().filename().string(), 0, 0});\n                }\n            }\n        }\n    }\n    \n    if (interfaces.empty())\n        SPDLOG_ERROR(\"Network: couldn't find any interfaces\");\n}\n\nlong long safe_stoll(const std::string& str, long long default_value);\nlong long safe_stoll(const std::string& str, long long default_value = 0) {\n    if (str.empty()) {\n        SPDLOG_DEBUG(\"tx or rx returned an empty string\");\n        return default_value;\n    }\n\n    try {\n        return std::stoll(str);\n    } catch (const std::invalid_argument& e) {\n        SPDLOG_DEBUG(\"stoll invalid argument\");\n    } catch (const std::out_of_range& e) {\n        SPDLOG_DEBUG(\"stoll out of range\");\n    }\n    return default_value;\n}\n\nvoid Net::update() {\n    if (!interfaces.empty()) {\n        for (auto& iface : interfaces) {\n            // path to tx_bytes and rx_bytes\n            std::string txfile = (NETDIR + iface.name + TXFILE);\n            std::string rxfile = (NETDIR + iface.name + RXFILE);\n            \n            // amount of bytes at previous update\n            uint64_t prevTx = iface.txBytes;\n            uint64_t prevRx = iface.rxBytes;\n            \n            // current amount of bytes\n            iface.txBytes = safe_stoll(read_line(txfile));\n            iface.rxBytes = safe_stoll(read_line(rxfile));\n\n            auto now = std::chrono::steady_clock::now();\n            // calculate the bytes per second since last update\n            iface.txBps = calculateThroughput(iface.txBytes, prevTx, iface.previousTime, now);\n            iface.rxBps = calculateThroughput(iface.rxBytes, prevRx, iface.previousTime, now);\n            iface.previousTime = now;\n        }\n    }\n}\n\nuint64_t Net::calculateThroughput(long long currentBytes, long long previousBytes,\n                                std::chrono::steady_clock::time_point previousTime,\n                                std::chrono::steady_clock::time_point currentTime) {\n    std::chrono::duration<double> elapsed = (currentTime - previousTime);\n    return static_cast<long long>((currentBytes - previousBytes) / elapsed.count());\n}\n"
  },
  {
    "path": "src/net.h",
    "content": "#pragma once\n#include <vector>\n#include <string>\n#include <stdint.h>\n#include \"filesystem.h\"\n#include \"file_utils.h\"\n#include <spdlog/spdlog.h>\n#include <iostream>\n\nnamespace fs = ghc::filesystem;\n\n#ifndef NETDIR\n#define NETDIR \"/sys/class/net/\"\n#endif\n\n#ifndef TXFILE\n#define TXFILE \"/statistics/tx_bytes\"\n#endif\n\n#ifndef RXFILE\n#define RXFILE \"/statistics/rx_bytes\"\n#endif\n\nclass Net {\n    public:\n        bool should_reset = false;\n        struct networkInterface {\n            std::string name;\n            uint64_t txBytes;\n            uint64_t rxBytes;\n            uint64_t txBps;\n            uint64_t rxBps;\n            std::chrono::steady_clock::time_point previousTime;\n        };\n\n        Net();\n        void update();\n        std::vector<networkInterface> interfaces = {};\n\n    private:\n        uint64_t calculateThroughput(long long currentBytes, long long previousBytes,\n                            std::chrono::steady_clock::time_point previousTime,\n                            std::chrono::steady_clock::time_point currentTime);\n};\n\nextern std::unique_ptr<Net> net;"
  },
  {
    "path": "src/notify.cpp",
    "content": "#include <chrono>\n#include <unistd.h>\n#include <fcntl.h>\n#include <sys/types.h>\n#include <sys/inotify.h>\n#include <spdlog/spdlog.h>\n#include \"config.h\"\n#include \"notify.h\"\n\n#define EVENT_SIZE  ( sizeof (struct inotify_event) )\n#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )\n\nstatic void fileChanged(notify_thread *nt) {\n    int length, i = 0;\n    char buffer[EVENT_BUF_LEN];\n    overlay_params local_params = *nt->params;\n\n    while (!nt->quit) {\n        length = read( nt->fd, buffer, EVENT_BUF_LEN );\n        while (i < length) {\n            struct inotify_event *event =\n                (struct inotify_event *) &buffer[i];\n            i += EVENT_SIZE + event->len;\n            if (event->mask & IN_MODIFY || event->mask & IN_DELETE_SELF) {\n                // In the case of IN_DELETE_SELF, some editors may do a save-to-temp-file/delete-original/move-temp-file\n                // so sleep a little to let file to be replaced\n                std::this_thread::sleep_for(std::chrono::milliseconds(100));\n                parse_overlay_config(&local_params, getenv(\"MANGOHUD_CONFIG\"), false);\n                if ((event->mask & IN_DELETE_SELF) || (nt->params->config_file_path != local_params.config_file_path)) {\n                    SPDLOG_DEBUG(\"Watching config file: {}\", local_params.config_file_path.c_str());\n                    inotify_rm_watch(nt->fd, nt->wd);\n                    nt->wd = inotify_add_watch(nt->fd, local_params.config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF);\n                }\n                std::lock_guard<std::mutex> lk(nt->mutex);\n                *nt->params = local_params;\n            }\n        }\n        i = 0;\n        std::this_thread::sleep_for(std::chrono::milliseconds(100));\n    }\n}\n\nbool start_notifier(notify_thread& nt)\n{\n    nt.fd = inotify_init1(IN_NONBLOCK);\n    if (nt.fd < 0) {\n        SPDLOG_ERROR(\"inotify_init1 failed: {}\", strerror(errno));\n        return false;\n    }\n\n    nt.wd = inotify_add_watch(nt.fd, nt.params->config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF);\n    if (nt.wd < 0) {\n        close(nt.fd);\n        nt.fd = -1;\n        return false;\n    }\n\n    if (nt.thread.joinable())\n        nt.thread.join();\n    nt.thread = std::thread(fileChanged, &nt);\n    return true;\n}\n\nvoid stop_notifier(notify_thread& nt)\n{\n    if (nt.fd < 0)\n        return;\n\n    nt.quit = true;\n    if (nt.thread.joinable())\n        nt.thread.join();\n    inotify_rm_watch(nt.fd, nt.wd);\n    close(nt.fd);\n    nt.fd = -1;\n}\n"
  },
  {
    "path": "src/notify.h",
    "content": "#pragma once\n#ifndef MANGOHUD_NOTIFY_H\n#define MANGOHUD_NOTIFY_H\n\n#include <thread>\n#include <mutex>\n#include \"overlay_params.h\"\n\nstruct notify_thread\n{\n    int fd = -1, wd = -1;\n    overlay_params *params = nullptr;\n    bool quit = false;\n    std::mutex mutex;\n    std::thread thread;\n};\n\nbool start_notifier(notify_thread& nt);\nvoid stop_notifier(notify_thread& nt);\n\n#endif //MANGOHUD_NOTIFY_H\n"
  },
  {
    "path": "src/nvapi.cpp",
    "content": "#include <windows.h>\n#include <iostream>\n#include \"gpu.h\"\n\n// magic numbers, do not change them\n#define NVAPI_MAX_PHYSICAL_GPUS   64\n#define NVAPI_MAX_USAGES_PER_GPU  34\n\n// function pointer types\ntypedef int *(*NvAPI_QueryInterface_t)(unsigned int offset);\ntypedef int (*NvAPI_Initialize_t)();\ntypedef int (*NvAPI_EnumPhysicalGPUs_t)(int **handles, int *count);\ntypedef int (*NvAPI_GPU_GetUsages_t)(int *handle, unsigned int *usages);\n\nNvAPI_QueryInterface_t      NvAPI_QueryInterface     = NULL;\nNvAPI_Initialize_t          NvAPI_Initialize         = NULL;\nNvAPI_EnumPhysicalGPUs_t    NvAPI_EnumPhysicalGPUs   = NULL;\nNvAPI_GPU_GetUsages_t       NvAPI_GPU_GetUsages      = NULL;\nHMODULE hmod;\nbool init_nvapi_bool;\nint         *gpuHandles[NVAPI_MAX_PHYSICAL_GPUS] = { NULL };\nint          gpuCount = 0;\nunsigned int gpuUsages[NVAPI_MAX_USAGES_PER_GPU] = { 0 };\n\nbool checkNVAPI(){\n\n#if _WIN64\n    hmod = LoadLibraryA(\"nvapi64.dll\");\n#else\n    hmod = LoadLibraryA(\"nvapi.dll\");\n#endif\n\n    if (hmod == NULL)\n    {\n        printf(\"Failed to load nvapi.dll\");\n        return false;\n    }\n    NvAPI_QueryInterface = (NvAPI_QueryInterface_t) GetProcAddress(hmod, \"nvapi_QueryInterface\");\n    NvAPI_Initialize = (NvAPI_Initialize_t) (*NvAPI_QueryInterface)(0x0150E828);\n    NvAPI_EnumPhysicalGPUs = (NvAPI_EnumPhysicalGPUs_t) (*NvAPI_QueryInterface)(0xE5AC921F);\n    NvAPI_GPU_GetUsages = (NvAPI_GPU_GetUsages_t) (*NvAPI_QueryInterface)(0x189A1FDF);\n    if (NvAPI_Initialize == NULL || NvAPI_EnumPhysicalGPUs == NULL ||\n        NvAPI_EnumPhysicalGPUs == NULL || NvAPI_GPU_GetUsages == NULL)\n    {\n        std::cerr << \"Couldn't get functions in nvapi.dll\" << std::endl;\n        return 2;\n    }\n    (*NvAPI_Initialize)();\n    \n    int         *gpuHandles[NVAPI_MAX_PHYSICAL_GPUS] = { NULL };\n\n    return true;\n}\n\nvoid nvapi_util()\n{  \n    if (!init_nvapi_bool){\n        init_nvapi_bool = checkNVAPI();\n    }\n    \n    gpuUsages[0] = (NVAPI_MAX_USAGES_PER_GPU * 4) | 0x10000;\n    (*NvAPI_EnumPhysicalGPUs)(gpuHandles, &gpuCount);\n    (*NvAPI_GPU_GetUsages)(gpuHandles[0], gpuUsages);\n    // TODO: create a GPU class for nvapi\n    // otherwise we can't display information\n    // gpu_info.load = gpuUsages[3];\n\n}"
  },
  {
    "path": "src/nvidia.cpp",
    "content": "#ifdef HAVE_NVML\n#include \"nvml.h\"\n#endif\n#include \"hud_elements.h\"\n#include \"logging.h\"\n#include \"string_utils.h\"\n#include <thread>\n#include <chrono>\n#include \"mesa/util/macros.h\"\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\nvoid NVIDIA::parse_token(const std::string& token, std::unordered_map<std::string, std::string>& options) {\n    std::string param, value;\n\n    size_t equal = token.find('=');\n    if (equal == std::string::npos)\n        return;\n\n    value = token.substr(equal+1);\n\n    param = token.substr(0, equal);\n    trim(param);\n    trim(value);\n    if (!param.empty())\n        options[param] = value;\n}\n#endif\n\nNVIDIA::NVIDIA(const char* pciBusId) {\n#ifdef HAVE_NVML\n    if (nvml && nvml->IsLoaded()) {\n        nvmlReturn_t result = nvml->nvmlInit_v2();\n        if (NVML_SUCCESS != result) {\n            SPDLOG_ERROR(\"Nvidia module initialization failed: {}\", nvml->nvmlErrorString(result));\n            nvml_available = false;\n        } else {\n            nvml_available = true; // NVML initialized successfully\n            if (pciBusId) {\n                result = nvml->nvmlDeviceGetHandleByPciBusId_v2(pciBusId, &device);\n                if (NVML_SUCCESS != result) {\n                    SPDLOG_ERROR(\"Getting device handle by PCI bus ID failed: {}\", nvml->nvmlErrorString(result));\n                    nvml_available = false; // Revert if getting device handle fails\n                }\n            }\n        }\n    }\n#endif\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\n    if (!get_libx11()->IsLoaded())\n        SPDLOG_DEBUG(\"XNVCtrl: X11 not loaded\");\n\n    if (!nvctrl || !nvctrl->IsLoaded()) {\n        SPDLOG_DEBUG(\"XNVCtrl loader failed to load\");\n        nvctrl_available = false;\n    } else {\n        nvctrl_available = find_nv_x11(display);\n    }\n\n    if (nvctrl && nvctrl_available) {\n        nvctrl->XNVCTRLQueryTargetCount(display,\n            NV_CTRL_TARGET_TYPE_COOLER,\n            &num_coolers);\n    }\n\n#endif\n\n    if (nvml_available || nvctrl_available) {\n        throttling = std::make_shared<Throttling>(0x10de);\n        thread = std::thread(&NVIDIA::get_samples_and_copy, this);\n        pthread_setname_np(thread.native_handle(), \"mangohud-nvidia\");\n    } else {\n        SPDLOG_WARN(\"NVML and NVCTRL are unavailable. Unable to get NVIDIA info. User is on DFSG version of mangohud?\");\n    }\n}\n\n#ifdef HAVE_NVML\nvoid NVIDIA::get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overlay_params *params) {\n    nvmlReturn_t response;\n\n    if (nvml && nvml_available) {\n        nvml_get_process_info();\n\n        struct nvmlUtilization_st nvml_utilization;\n        response = nvml->nvmlDeviceGetUtilizationRates(device, &nvml_utilization);\n        if (response == NVML_ERROR_NOT_SUPPORTED) {\n            SPDLOG_ERROR(\"nvmlDeviceGetUtilizationRates failed, disabling nvml metrics\");\n\n            nvml_available = false;\n            return;\n        }\n\n        metrics->load = nvml_utilization.gpu;\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] || (logger && logger->is_active())) {\n            unsigned int temp;\n            nvml->nvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &temp);\n            metrics->temp = temp;\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_vram] || (logger && logger->is_active())) {\n            struct nvmlMemory_st nvml_memory;\n            nvml->nvmlDeviceGetMemoryInfo(device, &nvml_memory);\n            metrics->memoryTotal = nvml_memory.total / (1024.f * 1024.f * 1024.f);\n            metrics->sys_vram_used = nvml_memory.used / (1024.f * 1024.f * 1024.f);\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_proc_vram])\n            metrics->proc_vram_used = get_proc_vram() / (1024.f * 1024.f * 1024.f);\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] || (logger && logger->is_active())) {\n            unsigned int core_clock;\n            nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &core_clock);\n            metrics->CoreClock = core_clock;\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock] || (logger && logger->is_active())) {\n            unsigned int memory_clock;\n            nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_MEM, &memory_clock);\n            metrics->MemClock = memory_clock;\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_power] || (logger && logger->is_active())) {\n            unsigned int power, limit;\n            nvml->nvmlDeviceGetPowerUsage(device, &power);\n            nvml->nvmlDeviceGetPowerManagementLimit(device, &limit);\n            metrics->powerUsage = power / 1000;\n            metrics->powerLimit = limit / 1000;\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_throttling_status]) {\n            unsigned long long nvml_throttle_reasons;\n            nvml->nvmlDeviceGetCurrentClocksThrottleReasons(device, &nvml_throttle_reasons);\n            metrics->is_temp_throttled = (nvml_throttle_reasons & 0x0000000000000060LL) != 0;\n            metrics->is_power_throttled = (nvml_throttle_reasons & 0x000000000000008CLL) != 0;\n            metrics->is_other_throttled = (nvml_throttle_reasons & 0x0000000000000112LL) != 0;\n            if (throttling)\n\t\t        throttling->indep_throttle_status = nvml_throttle_reasons;\n        }\n\n        if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] || (logger && logger->is_active())){\n            unsigned int fan_speed;\n            nvml->nvmlDeviceGetFanSpeed(device, &fan_speed);\n            metrics->fan_speed = fan_speed;\n            metrics->fan_rpm = false;\n        }\n    #ifdef HAVE_XNVCTRL\n        if (nvctrl_available) {\n            metrics->fan_rpm = true;\n            metrics->fan_speed = NVIDIA::get_nvctrl_fan_speed();\n        }\n    #endif\n    }\n}\n#endif\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\nvoid NVIDIA::get_instant_metrics_xnvctrl(struct gpu_metrics *metrics) {\n    std::unordered_map<std::string, std::string> xnvctrl_params;\n    std::string token;\n\n    if (!display)\n        nvctrl_available = false;\n\n    if (nvctrl && nvctrl_available && !nvml_available) {\n\n        int enums[] = {\n            NV_CTRL_STRING_GPU_UTILIZATION,\n            NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS,\n            0 // keep null\n        };\n\n        for (size_t i=0; enums[i]; i++) {\n            char* str = get_attr_target_string(enums[i], NV_CTRL_TARGET_TYPE_GPU, 0);\n            if (!str)\n                continue;\n\n            std::stringstream ss (str);\n            while (std::getline(ss, token, ',')) {\n                parse_token(token, xnvctrl_params);\n            }\n            free(str);\n        }\n\n        if (!try_stoi(metrics->load, xnvctrl_params[\"graphics\"]))\n            metrics->load = 0;\n        if (!try_stoi(metrics->CoreClock, xnvctrl_params[\"nvclock\"]))\n            metrics->CoreClock = 0;\n        if (!try_stoi(metrics->MemClock, xnvctrl_params[\"memclock\"]))\n            metrics->MemClock = 0;\n\n        int64_t temp = 0;\n        nvctrl->XNVCTRLQueryTargetAttribute64(display,\n                            NV_CTRL_TARGET_TYPE_GPU,\n                            0,\n                            0,\n                            NV_CTRL_GPU_CORE_TEMPERATURE,\n                            &temp);\n        metrics->temp = temp;\n\n        int64_t memtotal = 0;\n        nvctrl->XNVCTRLQueryTargetAttribute64(display,\n                            NV_CTRL_TARGET_TYPE_GPU,\n                            0,\n                            0,\n                            NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY,\n                            &memtotal);\n        metrics->memoryTotal = static_cast<float>(memtotal) / 1024.f;\n\n        int64_t memused = 0;\n        nvctrl->XNVCTRLQueryTargetAttribute64(display,\n                            NV_CTRL_TARGET_TYPE_GPU,\n                            0,\n                            0,\n                            NV_CTRL_USED_DEDICATED_GPU_MEMORY,\n                            &memused);\n        metrics->sys_vram_used = static_cast<float>(memused) / 1024.f;\n\n        metrics->fan_speed = NVIDIA::get_nvctrl_fan_speed();\n    }\n}\n#endif\n\nvoid NVIDIA::get_samples_and_copy() {\n    struct gpu_metrics metrics_buffer[METRICS_SAMPLE_COUNT] {};\n    auto logger_ref = logger; // inc ref count, to avoid destruction of logger.\n    auto params = get_params();\n    auto params_p = params.get(); // avoid destruction while we are getting samples...\n    while(!stop_thread) {\n#ifndef TEST_ONLY\n        if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid) {\n            pid = HUDElements.g_gamescopePid;\n        }\n#endif\n\n        for (size_t cur_sample_id=0; cur_sample_id < METRICS_SAMPLE_COUNT; cur_sample_id++) {\n#ifdef HAVE_NVML\n        if (nvml_available)\n            NVIDIA::get_instant_metrics_nvml(&metrics_buffer[cur_sample_id], params_p);\n#endif\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\n        if (nvctrl_available)\n            NVIDIA::get_instant_metrics_xnvctrl(&metrics_buffer[cur_sample_id]);\n#endif\n            usleep(METRICS_POLLING_PERIOD_MS * 1000);\n        }\n\n        if (stop_thread) break;\n\n        std::unique_lock<std::mutex> lock(metrics_mutex);\n        cond_var.wait(lock, [this]() { return !paused || stop_thread; });\n        GPU_UPDATE_METRIC_AVERAGE(load);\n        GPU_UPDATE_METRIC_AVERAGE_FLOAT(powerUsage);\n        GPU_UPDATE_METRIC_MAX(powerLimit);\n        GPU_UPDATE_METRIC_AVERAGE(CoreClock);\n        GPU_UPDATE_METRIC_AVERAGE(MemClock);\n\n        GPU_UPDATE_METRIC_AVERAGE(temp);\n\n        GPU_UPDATE_METRIC_AVERAGE_FLOAT(memoryTotal);\n        GPU_UPDATE_METRIC_AVERAGE_FLOAT(sys_vram_used);\n        GPU_UPDATE_METRIC_AVERAGE_FLOAT(proc_vram_used);\n\n        GPU_UPDATE_METRIC_MAX(is_power_throttled);\n        GPU_UPDATE_METRIC_MAX(is_current_throttled);\n        GPU_UPDATE_METRIC_MAX(is_temp_throttled);\n        GPU_UPDATE_METRIC_MAX(is_other_throttled);\n\n        GPU_UPDATE_METRIC_MAX(fan_speed);\n    }\n}\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\nint64_t NVIDIA::get_nvctrl_fan_speed(){\n    int64_t fan_speed = 0;\n    if (num_coolers >= 1) {\n        nvctrl->XNVCTRLQueryTargetAttribute64(display,\n                            NV_CTRL_TARGET_TYPE_COOLER,\n                            0,\n                            0,\n                            NV_CTRL_THERMAL_COOLER_SPEED,\n                            &fan_speed);\n    }\n    metrics.fan_rpm = true;\n    return fan_speed;\n}\n#endif\n\n#ifdef HAVE_XNVCTRL\nchar* NVIDIA::get_attr_target_string(int attr, int target_type, int target_id) {\n    char* c = nullptr;\n    if (nvctrl && !nvctrl->XNVCTRLQueryTargetStringAttribute(NVIDIA::display, target_type, target_id, 0, attr, &c)) {\n        SPDLOG_ERROR(\"Failed to query attribute '{}'\", attr);\n    }\n    return c;\n}\n#endif\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\nbool NVIDIA::find_nv_x11(Display*& dpy)\n{\n    const char *displayid = getenv(\"DISPLAY\");\n    auto libx11 = get_libx11();\n    if (displayid) {\n        Display *d = libx11->XOpenDisplay(displayid);\n        if (d) {\n            int s = libx11->XDefaultScreen(d);\n            if (nvctrl && nvctrl->XNVCTRLIsNvScreen(d, s)) {\n                dpy = d;\n                SPDLOG_DEBUG(\"XNVCtrl is using display {}\", displayid);\n                return true;\n            }\n            libx11->XCloseDisplay(d);\n        }\n    }\n    SPDLOG_DEBUG(\"XNVCtrl didn't find the correct display\");\n    return false;\n}\n#endif\n"
  },
  {
    "path": "src/nvidia.h",
    "content": "#pragma once\n#include \"gpu.h\"\n#ifdef HAVE_NVML\n#include \"loaders/loader_nvml.h\"\n#endif\n#ifdef HAVE_XNVCTRL\n#include \"loaders/loader_nvctrl.h\"\n#include \"loaders/loader_x11.h\"\n#endif\n\nclass NVIDIA {\n    public:\n        std::shared_ptr<Throttling> throttling;\n\n        bool nvml_available = false;\n        bool nvctrl_available = false;\n\n        gpu_metrics copy_metrics() {\n            std::lock_guard<std::mutex> lock(metrics_mutex);\n            return metrics;\n        };\n\n        void get_samples_and_copy();\n\n        NVIDIA(const char* pciBusId);\n        ~NVIDIA() {\n            stop_thread = true;\n            if (thread.joinable())\n                thread.join();\n        };\n\n#ifdef HAVE_NVML\n        void nvml_get_process_info() {\n            if (!nvml_available || !nvml)\n                return;\n\n            unsigned int infoCount = 0;\n\n            std::vector<nvmlProcessInfo_v1_t> cur_process_info(infoCount);\n            nvmlReturn_t ret = nvml->nvmlDeviceGetGraphicsRunningProcesses(device, &infoCount, cur_process_info.data());\n\n            if (ret != NVML_ERROR_INSUFFICIENT_SIZE)\n                return;\n\n            cur_process_info.resize(infoCount);\n            ret = nvml->nvmlDeviceGetGraphicsRunningProcesses(device, &infoCount, cur_process_info.data());\n\n            if (ret != NVML_SUCCESS)\n                return;\n\n            process_info = cur_process_info;\n        };\n\n        std::vector<int> pids() {\n            std::vector<int> vec;\n\n            for (const auto& proc : process_info)\n                vec.push_back(static_cast<int> (proc.pid));\n\n            return vec;\n        };\n\n        float get_proc_vram() {\n            for (const auto& proc : process_info) {\n                if (static_cast<pid_t>(proc.pid) != pid)\n                    continue;\n\n                return static_cast<float>(proc.usedGpuMemory);\n            }\n\n            return 0.f;\n        };\n#endif        \n\n        void pause() {\n            paused = true;\n            cond_var.notify_one();\n        };\n\n        void resume() {\n            paused = false;\n            cond_var.notify_one();\n        }\n\n    private:\n        pid_t pid = getpid();\n        std::mutex metrics_mutex;\n        gpu_metrics metrics;\n        std::thread thread;\n        std::condition_variable cond_var;\n        std::atomic<bool> stop_thread{false};\n        std::atomic<bool> paused{false};\n\n#ifdef HAVE_NVML\n        nvmlDevice_t device;\n\n        std::vector<nvmlProcessInfo_v1_t> process_info = {};\n\n        void get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overlay_params *params);\n        std::shared_ptr<libnvml_loader> nvml = get_libnvml_loader();\n#endif\n\n#if defined(HAVE_XNVCTRL) && defined(HAVE_X11)\n        Display* display;\n        // std::unique_ptr<Display, std::function<void(Display*)>> display;\n        int num_coolers;\n        int64_t get_nvctrl_fan_speed();\n        std::shared_ptr<libnvctrl_loader> nvctrl = get_libnvctrl_loader();\n\n        void get_instant_metrics_xnvctrl(struct gpu_metrics *metrics);\n        void parse_token(const std::string& token, std::unordered_map<std::string, std::string>& options);\n        bool find_nv_x11(Display*& dpy);\n        char* get_attr_target_string(int attr, int target_type, int target_id);\n#endif\n};\n"
  },
  {
    "path": "src/overlay.cpp",
    "content": "#include <sstream>\n#include <iomanip>\n#include <algorithm>\n#include <thread>\n#include <condition_variable>\n#include <spdlog/spdlog.h>\n#include <spdlog/cfg/env.h>\n#include <spdlog/sinks/stdout_color_sinks.h>\n#include <spdlog/sinks/rotating_file_sink.h>\n#include <filesystem.h>\n// #include <sys/stat.h>\n#include \"overlay.h\"\n#include \"cpu.h\"\n#include \"gpu.h\"\n#include \"hud_elements.h\"\n#include \"memory.h\"\n#include \"timing.hpp\"\n#include \"fcat.h\"\n#include \"mesa/util/macros.h\"\n#include \"battery.h\"\n#include \"device.h\"\n#include \"string_utils.h\"\n#include \"file_utils.h\"\n#include \"pci_ids.h\"\n#include \"iostats.h\"\n#include \"amdgpu.h\"\n#include \"fps_metrics.h\"\n#include \"net.h\"\n#include \"fex.h\"\n#include \"ftrace.h\"\n\n#ifdef __linux__\n#include <libgen.h>\n#include <unistd.h>\n#endif\n\nnamespace fs = ghc::filesystem;\nusing namespace std;\n\nstring gpuString,wineVersion,wineProcess;\nuint32_t deviceID;\nbool gui_open = false;\nbool fcat_open = false;\nstruct benchmark_stats benchmark;\nImVec2 real_font_size;\nstd::deque<logData> graph_data;\noverlay_params *_params {};\ndouble min_frametime, max_frametime;\nbool gpu_metrics_exists = false;\nbool steam_focused = false;\nvector<float> frametime_data(200,0.f);\nint fan_speed;\nfcatoverlay fcatstatus;\nstd::string drm_dev;\nint current_preset;\n\nvoid init_spdlog()\n{\n   if (spdlog::get(\"MANGOHUD\"))\n      return;\n\n   spdlog::set_default_logger(spdlog::stderr_color_mt(\"MANGOHUD\")); // Just to get the name in log\n   if (getenv(\"MANGOHUD_USE_LOGFILE\"))\n   {\n      try\n      {\n         // Not rotating when opening log as proton/wine create multiple (sub)processes\n         auto log = std::make_shared<spdlog::sinks::rotating_file_sink_mt> (get_config_dir() + \"/MangoHud/MangoHud.log\", 10*1024*1024, 5, false);\n         spdlog::get(\"MANGOHUD\")->sinks().push_back(log);\n      }\n      catch (const spdlog::spdlog_ex &ex)\n      {\n         SPDLOG_ERROR(\"{}\", ex.what());\n      }\n   }\n#ifdef DEBUG\n   spdlog::set_level(spdlog::level::level_enum::debug);\n#endif\n   spdlog::cfg::load_env_levels();\n\n   // Use MANGOHUD_LOG_LEVEL to correspond to SPDLOG_LEVEL\n   if (getenv(\"MANGOHUD_LOG_LEVEL\")) {\n      std::string log_level = getenv(\"MANGOHUD_LOG_LEVEL\");\n      vector<string> levels;\n      levels = {\"trace\",\"debug\",\"info\",\"warning\",\"error\",\"critical\",\"off\"};\n      for (auto & element : levels) {\n         transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower);\n         if(log_level == element ) {\n            spdlog::set_level(spdlog::level::from_str(log_level));\n         }\n      }\n#ifndef DEBUG\n   } else {\n      std::string log_level = \"info\";\n      transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower);\n      spdlog::set_level(spdlog::level::from_str(log_level));\n#endif\n   }\n\n}\n\nvoid update_hw_info(const struct overlay_params& params, uint32_t vendorID)\n{\n   auto real_params = get_params();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_fan])\n      update_fan();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats] || logger->is_active()) {\n      cpuStats.UpdateCPUData();\n\n#ifdef __linux__\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_core_load] || real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz] || logger->is_active())\n         cpuStats.UpdateCoreMhz();\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp] || logger->is_active() || real_params->enabled[OVERLAY_PARAM_ENABLED_graphs])\n         cpuStats.UpdateCpuTemp();\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_power] || logger->is_active())\n         cpuStats.UpdateCpuPower();\n#endif\n   }\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || logger->is_active()) {\n      if (gpus)\n         gpus->get_metrics();\n   }\n\n#ifdef __linux__\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_battery])\n      Battery_Stats.update();\n   if (!real_params->device_battery.empty()) {\n      device_update(params);\n      if (device_found) {\n            device_info();\n      }\n   }\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_ram] || real_params->enabled[OVERLAY_PARAM_ENABLED_swap] || logger->is_active())\n      update_meminfo();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_ram_temp])\n      update_mem_temp();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_procmem])\n      update_procmem();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_io_read] || real_params->enabled[OVERLAY_PARAM_ENABLED_io_write])\n      getIoStats(g_io_stats);\n#endif\n   if (gpus && gpus->active_gpu()) {\n      currentLogData.gpu_load = gpus->active_gpu()->metrics.load;\n      currentLogData.gpu_temp = gpus->active_gpu()->metrics.temp;\n      currentLogData.gpu_core_clock = gpus->active_gpu()->metrics.CoreClock;\n      currentLogData.gpu_mem_clock = gpus->active_gpu()->metrics.MemClock;\n      currentLogData.gpu_vram_used = gpus->active_gpu()->metrics.sys_vram_used;\n      currentLogData.gpu_power = gpus->active_gpu()->metrics.powerUsage;\n   }\n#ifdef __linux__\n   currentLogData.ram_used = memused;\n   currentLogData.swap_used = swapused;\n   currentLogData.process_rss = proc_mem_resident / float((2 << 29)); // GiB, consistent w/ other mem stats\n#endif\n\n   currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent;\n   currentLogData.cpu_temp = cpuStats.GetCPUDataTotal().temp;\n   currentLogData.cpu_power = cpuStats.GetCPUDataTotal().power;\n   currentLogData.cpu_mhz = cpuStats.GetCPUDataTotal().cpu_mhz;\n\n   // Save data for graphs\n   if (graph_data.size() >= kMaxGraphEntries)\n      graph_data.pop_front();\n   graph_data.push_back(currentLogData);\n   if (logger) logger->notify_data_valid();\n   HUDElements.update_exec();\n}\n\nstruct hw_info_updater\n{\n   bool quit = false;\n   std::thread thread {};\n   const struct overlay_params* params = nullptr;\n   uint32_t vendorID;\n   bool update_hw_info_thread = false;\n\n   std::condition_variable cv_hwupdate;\n   std::mutex m_cv_hwupdate, m_hw_updating;\n\n   hw_info_updater()\n   {\n      thread = std::thread(&hw_info_updater::run, this);\n      // Anything longer than this wouldn't fit in the 15 byte limit\n      pthread_setname_np(thread.native_handle(), \"mangohud-hwinfo\");\n   }\n\n   ~hw_info_updater()\n   {\n      quit = true;\n      cv_hwupdate.notify_all();\n      if (thread.joinable())\n         thread.join();\n   }\n\n   void update(const struct overlay_params* params_, uint32_t vendorID_)\n   {\n      std::unique_lock<std::mutex> lk_hw_updating(m_hw_updating, std::try_to_lock);\n      if (lk_hw_updating.owns_lock())\n      {\n         params = params_;\n         vendorID = vendorID_;\n         update_hw_info_thread = true;\n         cv_hwupdate.notify_all();\n      }\n   }\n\n   void run(){\n      while (!quit){\n         std::unique_lock<std::mutex> lk_cv_hwupdate(m_cv_hwupdate);\n         cv_hwupdate.wait(lk_cv_hwupdate, [&]{ return update_hw_info_thread || quit; });\n         if (quit) break;\n\n         if (params)\n         {\n            std::unique_lock<std::mutex> lk_hw_updating(m_hw_updating);\n            update_hw_info(*params, vendorID);\n         }\n         update_hw_info_thread = false;\n      }\n   }\n};\n\nstatic std::unique_ptr<hw_info_updater> hw_update_thread;\n\nvoid stop_hw_updater()\n{\n   if (hw_update_thread)\n      hw_update_thread.reset();\n}\n\nvoid update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID, uint64_t frametime_ns){\n   auto real_params = get_params();\n   uint32_t f_idx = sw_stats.n_frames % ARRAY_SIZE(sw_stats.frames_stats);\n   uint64_t now = os_time_get_nano(); /* ns */\n   auto elapsed = now - sw_stats.last_fps_update; /* ns */\n   float frametime_ms = frametime_ns / 1000000.f;\n\n   if (sw_stats.last_present_time) {\n        sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] =\n            frametime_ns;\n      frametime_data.push_back(frametime_ms);\n      frametime_data.erase(frametime_data.begin());\n   }\n#ifdef __linux__\n   if (gpus)\n      gpus->update_throttling();\n#endif\n#ifdef HAVE_FEX\n   fex::update_fex_stats();\n#endif\n#ifdef HAVE_FTRACE\n   if (real_params->ftrace.enabled) {\n      if (!FTrace::object)\n         FTrace::object = std::make_unique<FTrace::FTrace>(real_params->ftrace);\n      FTrace::object->update();\n   }\n#endif\n   frametime = frametime_ms;\n   fps = double(1000 / frametime_ms);\n   if (fpsmetrics) fpsmetrics->update(frametime_ms);\n\n   if (elapsed >= real_params->fps_sampling_period) {\n      if (!hw_update_thread)\n         hw_update_thread = std::make_unique<hw_info_updater>();\n      hw_update_thread->update(&params, vendorID);\n\n      if (fpsmetrics) fpsmetrics->update_thread();\n#ifdef __linux__\n      if (HUDElements.net) HUDElements.net->update();\n#endif\n\n      sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed;\n\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_time]) {\n         std::time_t t = std::time(nullptr);\n         std::stringstream time;\n         time << std::put_time(std::localtime(&t), real_params->time_format.c_str());\n         sw_stats.time = time.str();\n      }\n\n      if (real_params->autostart_log && logger && !logger->autostart_init) {\n         if ((std::chrono::steady_clock::now() - HUDElements.overlay_start) > std::chrono::seconds(real_params->autostart_log)){\n            logger->start_logging();\n            logger->autostart_init = true;\n         }\n      }\n\n      sw_stats.n_frames_since_update = 0;\n      sw_stats.last_fps_update = now;\n\n   }\n   auto min = std::min_element(frametime_data.begin(), frametime_data.end());\n   auto max = std::max_element(frametime_data.begin(), frametime_data.end());\n   min_frametime = min[0];\n   max_frametime = max[0];\n   // double min_time = UINT64_MAX, max_time = 0;\n   // for (auto& stat : sw_stats.frames_stats ){\n   //    min_time = MIN2(stat.stats[0], min_time);\n   //    max_time = MAX2(stat.stats[0], min_time);\n   // }\n   // min_frametime = min_time / sw_stats.time_dividor;\n   // max_frametime = max_time / sw_stats.time_dividor;\n   if (real_params->log_interval == 0){\n      logger->try_log();\n   }\n\n   sw_stats.last_present_time = now;\n   sw_stats.n_frames++;\n   sw_stats.n_frames_since_update++;\n}\n\nvoid update_hud_info(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID){\n   uint64_t now = os_time_get_nano(); /* ns */\n   uint64_t frametime_ns = now - sw_stats.last_present_time;\n   if (!get_params()->no_display || logger->is_active())\n      update_hud_info_with_frametime(sw_stats, params, vendorID, frametime_ns);\n}\n\nfloat get_time_stat(void *_data, int _idx)\n{\n   struct swapchain_stats *data = (struct swapchain_stats *) _data;\n   if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames)\n      return 0.0f;\n   int idx = ARRAY_SIZE(data->frames_stats) +\n      data->n_frames < ARRAY_SIZE(data->frames_stats) ?\n      _idx - data->n_frames :\n      _idx + data->n_frames;\n   idx %= ARRAY_SIZE(data->frames_stats);\n   /* Time stats are in us. */\n   return data->frames_stats[idx].stats[data->stat_selector] / data->time_dividor;\n}\n\nvoid overlay_new_frame(const struct overlay_params& params)\n{\n   ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);\n   ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(4,4));\n   ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,-3));\n   ImGui::PushStyleVar(ImGuiStyleVar_Alpha, params.alpha);\n   if (!params.enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5,5));\n   }\n   else {\n      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));\n   }\n}\n\nvoid overlay_end_frame()\n{\n   ImGui::PopStyleVar(5);\n}\n\nvoid position_layer(struct swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size)\n{\n   auto real_params = get_params();\n   unsigned width = ImGui::GetIO().DisplaySize.x;\n   unsigned height = ImGui::GetIO().DisplaySize.y;\n   float margin = 10.0f;\n   if (real_params->offset_x > 0 || real_params->offset_y > 0 || real_params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin])\n      margin = 0.0f;\n\n   ImGui::SetNextWindowBgAlpha(real_params->background_alpha);\n   ImGui::SetNextWindowSize(window_size, ImGuiCond_Always);\n   switch (real_params->position) {\n   case LAYER_POSITION_TOP_LEFT:\n      data.main_window_pos = ImVec2(margin + real_params->offset_x, margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_TOP_RIGHT:\n      data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_MIDDLE_LEFT:\n      data.main_window_pos = ImVec2(margin + params.offset_x, height / 2 - window_size.y / 2 - margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_MIDDLE_RIGHT:\n      data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, height / 2 - window_size.y / 2 - margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_BOTTOM_LEFT:\n      data.main_window_pos = ImVec2(margin +real_params->offset_x, height - window_size.y - margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_BOTTOM_RIGHT:\n      data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, height - window_size.y - margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_TOP_CENTER:\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) {\n         float content_width = ( real_params->table_columns  * 64);\n         data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2) - content_width, margin +  real_params->offset_y);\n      }\n      else\n         data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2), margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_BOTTOM_CENTER:\n      if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) {\n         float content_width = (real_params->table_columns  * 64);\n         data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2) - content_width,  height - window_size.y - margin + real_params->offset_y);\n      }\n      else\n         data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2), height - window_size.y - margin + real_params->offset_y);\n      ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always);\n      break;\n   case LAYER_POSITION_COUNT:\n      break;\n   }\n}\n\nvoid RenderOutlinedText(const char* text, ImU32 textColor) {\n   ImGuiWindow* window = ImGui::GetCurrentWindow();\n   ImGuiContext& g = *GImGui;\n   const ImGuiStyle& style = g.Style;\n\n   float outlineThickness = HUDElements.params->text_outline_thickness;\n   ImVec2 textSize = ImGui::CalcTextSize(text);\n   ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.text_outline);\n   ImVec2 pos = window->DC.CursorPos;\n\n   ImDrawList* drawList = ImGui::GetWindowDrawList();\n\n   if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_text_outline] && outlineThickness > 0.0f) {\n      drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x - outlineThickness, pos.y), outlineColor, text);\n      drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x + outlineThickness, pos.y), outlineColor, text);\n      drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x, pos.y - outlineThickness), outlineColor, text);\n      drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x, pos.y + outlineThickness), outlineColor, text);\n   }\n\n   drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), pos, textColor, text);\n\n   ImGui::ItemSize(textSize, style.FramePadding.y);\n}\n\nvoid right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...)\n{\n   ImVec2 pos = ImGui::GetCursorPos();\n   char buffer[32] {};\n\n   va_list args;\n   va_start(args, fmt);\n   vsnprintf(buffer, sizeof(buffer), fmt, args);\n   va_end(args);\n\n   if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){\n      ImVec2 sz = ImGui::CalcTextSize(buffer);\n      ImGui::SetCursorPosX(pos.x + off_x - sz.x);\n   }\n   RenderOutlinedText(buffer, ImGui::ColorConvertFloat4ToU32(col));\n   // ImGui::TextColored(col,\"%s\", buffer);\n}\n\nvoid center_text(const std::string& text)\n{\n   ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(text.c_str()).x / 2));\n}\n\n#ifdef HAVE_DBUS\nstatic float get_ticker_limited_pos(float pos, float tw, float& left_limit, float& right_limit)\n{\n   //float cw = ImGui::GetContentRegionAvailWidth() * 3; // only table cell worth of width\n   float cw = ImGui::GetWindowContentRegionMax().x - ImGui::GetStyle().WindowPadding.x;\n   float new_pos_x = ImGui::GetCursorPosX();\n   left_limit = cw - tw + new_pos_x;\n   right_limit = new_pos_x;\n\n   if (cw < tw) {\n      new_pos_x += pos;\n      // acts as a delay before it starts scrolling again\n      if (new_pos_x < left_limit)\n         return left_limit;\n      else if (new_pos_x > right_limit)\n         return right_limit;\n      else\n         return new_pos_x;\n   }\n   return new_pos_x;\n}\n\nvoid render_mpris_metadata(const struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing)\n{\n   static const float overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */;\n\n   if (meta.meta.valid) {\n      auto color = ImGui::ColorConvertU32ToFloat4(params.media_player_color);\n      ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,0));\n\n      if (!params.enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n         ImGui::Dummy(ImVec2(0.0f, 20.0f));\n      }\n\n      if (meta.ticker.needs_recalc) {\n         meta.ticker.formatted.clear();\n         meta.ticker.longest = 0;\n         for (const auto& f : params.media_player_format)\n         {\n            std::string str;\n            try\n            {\n               str = fmt::format(f,\n                                   fmt::arg(\"artist\", meta.meta.artists),\n                                   fmt::arg(\"title\", meta.meta.title),\n                                   fmt::arg(\"album\", meta.meta.album));\n            }\n            catch (const fmt::format_error& err)\n            {\n               SPDLOG_ERROR(\"formatting error in '{}': {}\", f, err.what());\n            }\n            float w = ImGui::CalcTextSize(str.c_str()).x;\n            meta.ticker.longest = std::max(meta.ticker.longest, w);\n            meta.ticker.formatted.push_back({str, w});\n         }\n         meta.ticker.needs_recalc = false;\n      }\n\n      float new_pos, left_limit = 0, right_limit = 0;\n      get_ticker_limited_pos(meta.ticker.pos, meta.ticker.longest, left_limit, right_limit);\n\n      if (meta.ticker.pos < left_limit - overflow * .5f) {\n         meta.ticker.dir = -1;\n         meta.ticker.pos = (left_limit - overflow * .5f) + 1.f /* random */;\n      } else if (meta.ticker.pos > right_limit + overflow) {\n         meta.ticker.dir = 1;\n         meta.ticker.pos = (right_limit + overflow) - 1.f /* random */;\n      }\n\n      meta.ticker.pos -= .5f * (frame_timing / 16666666.7f /* ns */) * meta.ticker.dir;\n\n      for (const auto& fmt : meta.ticker.formatted)\n      {\n         if (fmt.text.empty()) continue;\n         new_pos = get_ticker_limited_pos(meta.ticker.pos, fmt.width, left_limit, right_limit);\n         ImGui::SetCursorPosX(new_pos);\n         HUDElements.TextColored(color, \"%s\", fmt.text.c_str());\n      }\n\n      ImGui::PopStyleVar();\n   }\n}\n#endif\n\nstatic void render_benchmark(swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size, unsigned height, Clock::time_point now){\n   // TODO, FIX LOG_DURATION FOR BENCHMARK\n   int benchHeight = (2 + benchmark.percentile_data.size()) * real_font_size.x + 10.0f + 58;\n   ImGui::SetNextWindowSize(ImVec2(window_size.x, benchHeight), ImGuiCond_Always);\n   if (height - (window_size.y + data.main_window_pos.y + 5) < benchHeight)\n      ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y - benchHeight - 5), ImGuiCond_Always);\n   else\n      ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y + window_size.y + 5), ImGuiCond_Always);\n#ifdef MANGOAPP\n   ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y + window_size.y + 5), ImGuiCond_Always);\n#endif\n   float display_time = std::chrono::duration<float>(now - logger->last_log_end()).count();\n   static float display_for = 10.0f;\n   float alpha;\n   if (params.background_alpha != 0){\n      if (display_for >= display_time){\n         alpha = display_time * params.background_alpha;\n         if (alpha >= params.background_alpha){\n            ImGui::SetNextWindowBgAlpha(params.background_alpha);\n         }else{\n            ImGui::SetNextWindowBgAlpha(alpha);\n         }\n      } else {\n         alpha = 6.0 - display_time * params.background_alpha;\n         if (alpha >= params.background_alpha){\n            ImGui::SetNextWindowBgAlpha(params.background_alpha);\n         }else{\n            ImGui::SetNextWindowBgAlpha(alpha);\n         }\n      }\n   } else {\n      if (display_for >= display_time){\n         alpha = display_time * 0.0001;\n         ImGui::SetNextWindowBgAlpha(params.background_alpha);\n      } else {\n         alpha = 6.0 - display_time * 0.0001;\n         ImGui::SetNextWindowBgAlpha(params.background_alpha);\n      }\n   }\n\n   ImGui::Begin(\"Benchmark\", &gui_open, ImGuiWindowFlags_NoDecoration);\n   static const char* finished = \"Logging Finished\";\n   ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(finished).x / 2));\n   ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), \"%s\", finished);\n   ImGui::Dummy(ImVec2(0.0f, 8.0f));\n\n   char duration[20];\n   snprintf(duration, sizeof(duration), \"Duration: %.1fs\", std::chrono::duration<float>(logger->last_log_end() - logger->last_log_begin()).count());\n   ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(duration).x / 2));\n   ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), \"%s\", duration);\n   for (auto& data_ : benchmark.percentile_data){\n      char buffer[20];\n      snprintf(buffer, sizeof(buffer), \"%s %.1f\", data_.first.c_str(), data_.second);\n      ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(buffer).x / 2));\n      ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), \"%s %.1f\", data_.first.c_str(), data_.second);\n   }\n\n   float max = benchmark.fps_data.empty() ? 0.0f : *max_element(benchmark.fps_data.begin(), benchmark.fps_data.end());\n   ImVec4 plotColor = HUDElements.colors.frametime;\n   plotColor.w = alpha / params.background_alpha;\n   ImGui::PushStyleColor(ImGuiCol_PlotLines, plotColor);\n   ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 0.0, 0.0, alpha / params.background_alpha));\n   ImGui::Dummy(ImVec2(0.0f, 8.0f));\n   if (params.enabled[OVERLAY_PARAM_ENABLED_histogram])\n      ImGui::PlotHistogram(\"##plot_histogram\", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, \"\", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50));\n   else\n      ImGui::PlotLines(\"##plot_lines\", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, \"\", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50));\n   ImGui::PopStyleColor(2);\n   ImGui::End();\n}\n\nImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current)\n{\n   if (current >= data.high_load){\n      return data.color_high;\n   }\n   else if (current >= data.med_load){\n      float diff = float(current - data.med_load) / float(data.high_load - data.med_load);\n      float x = (data.color_high.x - data.color_med.x) * diff;\n      float y = (data.color_high.y - data.color_med.y) * diff;\n      float z = (data.color_high.z - data.color_med.z) * diff;\n      return ImVec4(data.color_med.x + x, data.color_med.y + y, data.color_med.z + z, HUDElements.params->alpha);\n   } else {\n      float diff = float(current) / float(data.med_load);\n      float x = (data.color_med.x - data.color_low.x) * diff;\n      float y = (data.color_med.y - data.color_low.y) * diff;\n      float z = (data.color_med.z - data.color_low.z) * diff;\n      return ImVec4(data.color_low.x + x, data.color_low.y + y, data.color_low.z + z, HUDElements.params->alpha);\n   }\n}\n\nvoid horizontal_separator(struct overlay_params& params) {\n    ImGui::SameLine();\n    ImGui::Spacing();\n    ImGui::SameLine();\n\n    ImDrawList* drawList = ImGui::GetWindowDrawList();\n    ImVec2 cursorPos = ImGui::GetCursorScreenPos();\n    ImVec2 startPos(cursorPos.x - 5, cursorPos.y + 2);\n    ImVec2 endPos(startPos.x, cursorPos.y + params.font_size * 0.85);\n\n    float outlineThickness = 1.0f;\n\n   if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_text_outline]){\n      // Draw the black outline\n      drawList->AddLine(ImVec2(startPos.x - outlineThickness, startPos.y), ImVec2(startPos.x - outlineThickness, endPos.y), IM_COL32_BLACK, outlineThickness + 2);\n      drawList->AddLine(ImVec2(startPos.x + outlineThickness, startPos.y), ImVec2(startPos.x + outlineThickness, endPos.y), IM_COL32_BLACK, outlineThickness + 2);\n      drawList->AddLine(ImVec2(startPos.x - outlineThickness, startPos.y - outlineThickness/2), ImVec2(startPos.x + outlineThickness, startPos.y - outlineThickness/2), IM_COL32_BLACK, outlineThickness + 2);\n      drawList->AddLine(ImVec2(startPos.x - outlineThickness, endPos.y + outlineThickness/2), ImVec2(startPos.x + outlineThickness, endPos.y + outlineThickness/2), IM_COL32_BLACK, outlineThickness + 2);\n   } else {\n      outlineThickness *= 2;\n   }\n\n    // Draw the separator line\n    ImU32 separator_color = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.horizontal_separator);\n    drawList->AddLine(startPos, endPos, separator_color, outlineThickness);\n\n    ImGui::SameLine();\n    ImGui::Spacing();\n}\n\nvoid render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan)\n{\n   {\n      std::unique_lock<std::mutex> lock(config_mtx);\n      config_cv.wait(lock, []{ return config_ready; });\n   }\n   // data.engine = EngineTypes::GAMESCOPE;\n   HUDElements.sw_stats = &data;\n   auto real_params = get_params();\n   if (real_params)\n      HUDElements.params = real_params;\n\n   HUDElements.is_vulkan = is_vulkan;\n   ImGui::GetIO().FontGlobalScale = real_params->font_scale;\n   static float ralign_width = 0, old_scale = 0;\n   auto io = ImGui::GetIO();\n   if (real_params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){\n      window_size = ImVec2((to_string(int(HUDElements.sw_stats->fps)).length() * ImGui::CalcTextSize(\"A\").x) + 15.f, get_params()->height);\n   } else if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n      window_size = ImVec2(io.DisplaySize.x, real_params->height);\n   } else {\n      window_size = ImVec2(real_params->width, real_params->height);\n   }\n   unsigned height = io.DisplaySize.y;\n   auto now = Clock::now();\n\n   if (old_scale != real_params->font_scale) {\n      HUDElements.ralign_width = ralign_width = ImGui::CalcTextSize(\"A\").x * 4 /* characters */;\n      old_scale = real_params->font_scale;\n   }\n   ImGuiTableFlags table_flags = ImGuiTableFlags_NoClip;\n   if(real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal])\n      table_flags = ImGuiTableFlags_NoClip | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX;\n\n   if (!real_params->no_display && !steam_focused && get_params()->table_columns){\n      ImGui::Begin(\"Main\", &gui_open, ImGuiWindowFlags_NoDecoration);\n      if (ImGui::BeginTable(\"hud\", real_params->table_columns, table_flags )) {\n         HUDElements.place = 0;\n         for (auto& func : HUDElements.ordered_functions){\n            if(!real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.name != \"exec\")\n               ImGui::TableNextRow();\n            func.run();\n            HUDElements.place += 1;\n            if(!HUDElements.ordered_functions.empty() && real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && HUDElements.ordered_functions.size() != (size_t)HUDElements.place)\n               horizontal_separator(params);\n         }\n\n         if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n            if (HUDElements.table_columns_count > 0 && HUDElements.table_columns_count < 65 )\n               real_params->table_columns = HUDElements.table_columns_count;\n            if(!real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) {\n               float content_width = ImGui::GetContentRegionAvail().x - (real_params->table_columns * 64);\n               window_size = ImVec2(content_width, real_params->height);\n            }\n         }\n         ImGui::EndTable();\n         HUDElements.table_columns_count = 0;\n      }\n\n      if(logger->is_active())\n         ImGui::GetWindowDrawList()->AddCircleFilled(ImVec2(data.main_window_pos.x + window_size.x - 15, data.main_window_pos.y + 15), 10, real_params->engine_color, 20);\n      window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 11.0f);\n      ImGui::End();\n      if((now - logger->last_log_end()) < 12s && !logger->is_active())\n         render_benchmark(data, params, window_size, height, now);\n   }\n\n   if(real_params->enabled[OVERLAY_PARAM_ENABLED_fcat])\n     {\n       fcatstatus.update(&params);\n       auto window_corners = fcatstatus.get_overlay_corners();\n       auto p_min=window_corners[0];\n       auto p_max=window_corners[1];\n       auto window_size= window_corners[2];\n       ImGui::SetNextWindowPos(p_min, ImGuiCond_Always);\n       ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0));\n       ImGui::SetNextWindowSize(window_size);\n       ImGui::Begin(\"FCAT\", &fcat_open, ImGuiWindowFlags_NoDecoration| ImGuiWindowFlags_NoBackground);\n       ImGui::GetWindowDrawList()->AddRectFilled(p_min,p_max,fcatstatus.get_next_color(data),0.0);\n       ImGui::End();\n       ImGui::PopStyleVar();\n     }\n}\n\nvoid init_cpu_stats(overlay_params& params)\n{\n#ifdef __linux__\n   auto& enabled = params.enabled;\n   enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = cpuStats.Init()\n                           && enabled[OVERLAY_PARAM_ENABLED_cpu_stats];\n   enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = cpuStats.GetCpuFile()\n                           && enabled[OVERLAY_PARAM_ENABLED_cpu_temp];\n#endif\n}\n\nstruct pci_bus {\n   int domain;\n   int bus;\n   int slot;\n   int func;\n};\n\nvoid init_system_info(){\n   #ifdef __linux__\n      const char* ld_preload = getenv(\"LD_PRELOAD\");\n      if (ld_preload)\n         unsetenv(\"LD_PRELOAD\");\n\n      ram =  exec(\"sed -n 's/^MemTotal: *\\\\([0-9]*\\\\).*/\\\\1/p' /proc/meminfo\");\n      trim(ram);\n      cpu =  exec(\"sed -n 's/^model name.*: \\\\(.*\\\\)/\\\\1/p' /proc/cpuinfo | sed 's/([^)]*)//g' | tail -n1\");\n      trim(cpu);\n      kernel = exec(\"uname -r\");\n      trim(kernel);\n      os = exec(\"sed -n 's/PRETTY_NAME=\\\\(.*\\\\)/\\\\1/p' /etc/os-release\");\n      os.erase(remove(os.begin(), os.end(), '\\\"' ), os.end());\n      trim(os);\n      cpusched = read_line(\"/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor\");\n\n      const char* mangohud_recursion = getenv(\"MANGOHUD_RECURSION\");\n      if (!mangohud_recursion) {\n         setenv(\"MANGOHUD_RECURSION\", \"1\", 1);\n         // driver = exec(\"glxinfo -B | sed -n 's/^OpenGL version.*: \\\\(.*\\\\)/\\\\1/p' | sed 's/([^)]*)//g;s/  / /g'\");\n         // trim(driver);\n         unsetenv(\"MANGOHUD_RECURSION\");\n      } else {\n         driver = \"MangoHud glxinfo recursion detected\";\n      }\n\n// Get WINE version\n\n      wineProcess = get_exe_path();\n      auto n = wineProcess.find_last_of('/');\n      string preloader = wineProcess.substr(n + 1);\n      if (preloader == \"wine-preloader\" || preloader == \"wine64-preloader\") {\n         // Check if using Proton\n         if (wineProcess.find(\"/dist/bin/wine\") != std::string::npos\n            || wineProcess.find(\"/files/bin/wine\") != std::string::npos\n            || wineProcess.find(\"/dist/bin-wow64/wine\") != std::string::npos\n            || wineProcess.find(\"/files/bin-wow64/wine\") != std::string::npos)\n         {\n            stringstream ss;\n            ss << dirname((char*)wineProcess.c_str()) << \"/../../version\";\n            string protonVersion = ss.str();\n            ss.str(\"\"); ss.clear();\n            ss << read_line(protonVersion);\n            std::getline(ss, wineVersion, ' '); // skip first number string\n            std::getline(ss, wineVersion, ' ');\n            trim(wineVersion);\n            string toReplace = \"proton-\";\n            size_t pos = wineVersion.find(toReplace);\n            if (pos != std::string::npos) {\n               // If found replace\n               wineVersion.replace(pos, toReplace.length(), \"Proton \");\n            }\n            else {\n               // If not found insert for non official proton builds\n               wineVersion.insert(0, \"Proton \");\n            }\n         }\n         else {\n            char *dir = dirname((char*)wineProcess.c_str());\n            stringstream findVersion;\n            if (preloader == \"wine-preloader\")\n               findVersion << \"\\\"\" << dir << \"/wine\\\" --version\";\n            else\n               findVersion << \"\\\"\" << dir << \"/wine64\\\" --version\";\n            const char *wine_env = getenv(\"WINELOADERNOEXEC\");\n            if (wine_env)\n               unsetenv(\"WINELOADERNOEXEC\");\n            wineVersion = exec(findVersion.str());\n            trim(wineVersion);\n            SPDLOG_DEBUG(\"WINE version: {}\", wineVersion);\n            if (wine_env)\n               setenv(\"WINELOADERNOEXEC\", wine_env, 1);\n         }\n      }\n      else {\n           wineVersion = \"\";\n      }\n\n      check_for_vkbasalt_and_gamemode();\n\n      if (ld_preload)\n         setenv(\"LD_PRELOAD\", ld_preload, 1);\n\n      SPDLOG_DEBUG(\"Ram:{}\", ram);\n      SPDLOG_DEBUG(\"Cpu:{}\", cpu);\n      SPDLOG_DEBUG(\"Kernel:{}\", kernel);\n      SPDLOG_DEBUG(\"Os:{}\", os);\n      SPDLOG_DEBUG(\"Driver:{}\", driver);\n      SPDLOG_DEBUG(\"CPU Scheduler:{}\", cpusched);\n#endif\n}\n\nvoid check_for_vkbasalt_and_gamemode() {\n#ifdef __linux__\n   static bool checked = false;\n   if (checked)\n      return;\n\n   if (lib_loaded(\"gamemode\", HUDElements.g_gamescopePid))\n      HUDElements.gamemode_bol = true;\n\n   if (lib_loaded(\"vkbasalt\", HUDElements.g_gamescopePid))\n      HUDElements.vkbasalt_bol = true;\n\n   checked = true;\n#endif\n}\n\nvoid update_fan(){\n   // This just handles steam deck fan for now\n   static bool init;\n   string hwmon_path;\n\n   if (!init){\n      string path = \"/sys/class/hwmon/\";\n      auto dirs = ls(path.c_str(), \"hwmon\", LS_DIRS);\n      for (auto& dir : dirs) {\n         string full_path = (path + dir + \"/name\").c_str();\n         if (read_line(full_path).find(\"steamdeck_hwmon\") != string::npos){\n            hwmon_path = path + dir + \"/fan1_input\";\n            break;\n         }\n      }\n   }\n\n   if (!hwmon_path.empty())\n      fan_speed = stoi(read_line(hwmon_path));\n   else\n      fan_speed = -1;\n}\n\nvoid next_hud_position(){\n   auto params = get_params();\n   if (params->position < (overlay_param_position::LAYER_POSITION_COUNT - 1)){\n      params->position = static_cast<overlay_param_position>(params->position + 1);\n   } else {\n      params->position = static_cast<overlay_param_position>(0);\n   }\n}\n"
  },
  {
    "path": "src/overlay.frag",
    "content": "#version 450 core\nlayout(location = 0) out vec4 fColor;\n\nlayout(set=0, binding=0) uniform sampler2D sTexture;\n\nlayout(location = 0) in struct{\n    vec4 Color;\n    vec2 UV;\n} In;\n\nvoid main()\n{\n    fColor = In.Color * vec4(1, 1, 1, texture(sTexture, In.UV.st).r);\n}\n"
  },
  {
    "path": "src/overlay.h",
    "content": "#pragma once\n#ifndef MANGOHUD_OVERLAY_H\n#define MANGOHUD_OVERLAY_H\n\n#include <string>\n#include <stdint.h>\n#include <vector>\n#include <deque>\n#include <imgui.h>\n#include \"imgui_internal.h\"\n#include \"overlay_params.h\"\n#include \"hud_elements.h\"\n\n#include \"dbus_info.h\"\n#include \"logging.h\"\n\nstruct frame_stat {\n   uint64_t stats[OVERLAY_PLOTS_MAX];\n};\n\nstatic const int kMaxGraphEntries = 50;\n\nenum EngineTypes\n{\n   UNKNOWN,\n\n   OPENGL,\n   VULKAN,\n\n   DXVK,\n   VKD3D,\n   DAMAVAND,\n   ZINK,\n\n   WINED3D,\n   FERAL3D,\n   TOGL,\n\n   GAMESCOPE,\n   SDL\n};\n\nstruct swapchain_stats {\n   uint64_t n_frames;\n   enum overlay_plots stat_selector;\n   double time_dividor;\n   struct frame_stat stats_min, stats_max;\n   struct frame_stat frames_stats[200];\n\n   ImFont* font_small = nullptr;\n   ImFont* font_text = nullptr;\n   ImFont* font_secondary = nullptr;\n   size_t font_params_hash = 0;\n   std::string time;\n   double fps;\n   uint64_t last_present_time;\n   unsigned n_frames_since_update;\n   uint64_t last_fps_update;\n   ImVec2 main_window_pos;\n\n   struct {\n      int32_t major;\n      int32_t minor;\n      bool is_gles;\n   } version_gl;\n   struct {\n      int32_t major;\n      int32_t minor;\n      int32_t patch;\n   } version_vk;\n   std::string engineName;\n   std::string engineVersion;\n   std::string deviceName;\n   std::string gpuName;\n   std::string driverName;\n   uint32_t applicationVersion;\n   enum EngineTypes engine;\n};\n\nstruct benchmark_stats {\n   float total;\n   std::vector<float> fps_data;\n   std::vector<std::pair<std::string, float>> percentile_data;\n};\n\nstruct LOAD_DATA {\n   ImVec4 color_low;\n   ImVec4 color_med;\n   ImVec4 color_high;\n   unsigned med_load;\n   unsigned high_load;\n};\n\n\ninline const char* engine_name(const swapchain_stats& sw_stats) {\n   const char* engines[] = {\n      \"Unknown\", \"OpenGL\", \"VULKAN\", \"DXVK\", \"VKD3D\", \"DAMAVAND\",\n      \"ZINK\", \"WINED3D\", \"Feral3D\", \"ToGL\", \"GAMESCOPE\", \"SDL\"\n   };\n   const char* engines_short[] = {\n      \"Unknown\", \"OGL\", \"VK\", \"DXVK\", \"VKD3D\", \"DV\",\n       \"ZINK\", \"WD3D\", \"Feral3D\", \"ToGL\", \"GS\", \"SDL\"\n   };\n\n   auto engine = sw_stats.engine;\n   auto params = get_params();\n   if (!params)\n      return \"Unknown\";\n\n   if (!params->fps_text.empty())\n      return params->fps_text.c_str();\n\n   auto& en = params->enabled;\n\n   if (en[OVERLAY_PARAM_ENABLED_hide_engine_names]) {\n      en[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = true;\n      return \"FPS\";\n   }\n\n   if (en[OVERLAY_PARAM_ENABLED_horizontal] && !en[OVERLAY_PARAM_ENABLED_engine_short_names]) {\n      en[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = true;\n      return \"FPS\";\n   }\n\n   if (en[OVERLAY_PARAM_ENABLED_dx_api]) {\n      if (engine == EngineTypes::VKD3D)\n         return \"DX12\";\n\n      if (engine == EngineTypes::DXVK) {\n         if (sw_stats.applicationVersion == 1)\n            return \"DX9\";\n\n         if (sw_stats.applicationVersion == 2)\n            return \"DX11\";\n\n         return \"DX?\";\n      }\n   }\n\n   return en[OVERLAY_PARAM_ENABLED_engine_short_names] ? engines_short[engine] : engines[engine];\n}\n\nextern uint32_t deviceID;\n\nextern struct benchmark_stats benchmark;\nextern ImVec2 real_font_size;\nextern std::string wineVersion;\nextern std::deque<logData> graph_data;\nextern double min_frametime, max_frametime;\nextern bool steam_focused;\nextern int fan_speed;\nextern int current_preset;\nextern std::vector<float> frametime_data;\n\nvoid init_spdlog();\nvoid overlay_new_frame(const struct overlay_params& params);\nvoid overlay_end_frame();\nvoid position_layer(struct swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size);\nvoid render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan);\nvoid update_hud_info(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID);\nvoid update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID, uint64_t frametime_ns);\nvoid update_hw_info(const struct overlay_params& params, uint32_t vendorID);\nvoid init_cpu_stats(overlay_params& params);\nvoid check_keybinds(overlay_params& params);\nvoid init_system_info(void);\nvoid check_for_vkbasalt_and_gamemode();\nvoid create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font, ImFont*& secondary_font);\nvoid right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...);\nvoid center_text(const std::string& text);\nImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current);\nfloat get_time_stat(void *_data, int _idx);\nvoid stop_hw_updater();\nextern void control_client_check(int control, int& control_client, const std::string& deviceName);\nextern void process_control_socket(int& control_client, overlay_params &params);\nextern void control_send(int control_client, const char *cmd, unsigned cmdlen, const char *param, unsigned paramlen);\nextern int global_control_client;\n#ifdef HAVE_DBUS\nvoid render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);\n#endif\nvoid update_fan();\nvoid next_hud_position();\nvoid horizontal_separator(struct overlay_params& params);\nvoid RenderOutlinedText(const char* text, ImU32 textColor);\n#endif //MANGOHUD_OVERLAY_H\n"
  },
  {
    "path": "src/overlay.vert",
    "content": "#version 450 core\nlayout(location = 0) in vec2 aPos;\nlayout(location = 1) in vec2 aUV;\nlayout(location = 2) in vec4 aColor;\n\nlayout(push_constant) uniform uPushConstant{\n    vec2 uScale;\n    vec2 uTranslate;\n} pc;\n\nout gl_PerVertex{\n    vec4 gl_Position;\n};\n\nlayout(location = 0) out struct{\n    vec4 Color;\n    vec2 UV;\n} Out;\n\nvoid main()\n{\n    Out.Color = aColor;\n    Out.UV = aUV;\n    gl_Position = vec4(aPos*pc.uScale+pc.uTranslate, 0, 1);\n}\n"
  },
  {
    "path": "src/overlay_params.cpp",
    "content": "#include <cstdint>\n#ifdef _WIN32\n#include <windows.h>\n#endif\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <errno.h>\n#ifdef __linux__\n#include <wordexp.h>\n#include <unistd.h>\n#endif\n#include \"imgui.h\"\n#include <iostream>\n#include <string>\n#include <sstream>\n#include <fstream>\n#include <algorithm>\n#include <cctype>\n#include <array>\n#include <functional>\n#include <spdlog/spdlog.h>\n#include <vulkan/vulkan_core.h>\n\n#include \"overlay_params.h\"\n#include \"overlay.h\"\n#include \"config.h\"\n#include \"string_utils.h\"\n#include \"hud_elements.h\"\n#include \"blacklist.h\"\n#include \"mesa/util/os_socket.h\"\n#include \"file_utils.h\"\n#include \"fex.h\"\n#include \"ftrace.h\"\n#include \"fps_limiter.h\"\n\n#if defined(HAVE_X11) || defined(HAVE_WAYLAND)\n#include <xkbcommon/xkbcommon.h>\n#endif\n\n#include \"dbus_info.h\"\n\n#include \"app/mangoapp.h\"\n#include \"fps_metrics.h\"\n#include \"version.h\"\n\nstd::unique_ptr<fpsMetrics> fpsmetrics;\nstd::mutex config_mtx;\nstd::condition_variable config_cv;\nbool config_ready = false;\nstatic std::shared_ptr<overlay_params> g_params;\nstd::shared_ptr<fpsLimiter> fps_limiter;\n\n#if __cplusplus >= 201703L\n\ntemplate<typename... Ts>\nsize_t get_hash(Ts const&... args)\n{\n   size_t hash = 0;\n   ( (hash ^= std::hash<Ts>{}(args) << 1), ...);\n   return hash;\n}\n\n#else\n\n// C++17 has `if constexpr` so this won't be needed then\ntemplate<typename... Ts>\nsize_t get_hash()\n{\n   return 0;\n}\n\ntemplate<typename T, typename... Ts>\nsize_t get_hash(T const& first, Ts const&... rest)\n{\n   size_t hash = std::hash<T>{}(first);\n#if __cplusplus >= 201703L\n   if constexpr (sizeof...(rest) > 0)\n#endif\n      hash ^= get_hash(rest...) << 1;\n\n   return hash;\n}\n\n#endif\n\nnamespace {\nbool parse_vulkan_present_mode_name(std::string_view name, VkPresentModeKHR& mode) {\n   static constexpr std::string_view prefix = \"VK_PRESENT_MODE_\";\n   static constexpr std::string_view suffix = \"_KHR\";\n\n   static constexpr std::pair<std::string_view, VkPresentModeKHR> present_mode_table[] = {\n      { \"IMMEDIATE\", VK_PRESENT_MODE_IMMEDIATE_KHR },\n      { \"MAILBOX\", VK_PRESENT_MODE_MAILBOX_KHR },\n      { \"FIFO\", VK_PRESENT_MODE_FIFO_KHR },\n      { \"FIFO_RELAXED\", VK_PRESENT_MODE_FIFO_RELAXED_KHR },\n      { \"SHARED_DEMAND_REFRESH\", VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR },\n      { \"SHARED_CONTINUOUS_REFRESH\", VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR },\n      { \"FIFO_LATEST_READY\", VK_PRESENT_MODE_FIFO_LATEST_READY_KHR },\n   };\n\n   name = strip_prefix(name, prefix);\n   name = strip_suffix(name, suffix);\n\n   const auto elem = std::find_if(\n       std::begin(present_mode_table), std::end(present_mode_table),\n       [&](const auto &entry) { return iequal(entry.first, name); });\n\n   if (elem == std::end(present_mode_table))\n      return false;\n\n   mode = elem->second;\n\n   return true;\n}\n}\n\nstatic enum overlay_param_position\nparse_position(const char *str)\n{\n   if (!str || !strcmp(str, \"top-left\"))\n      return LAYER_POSITION_TOP_LEFT;\n   if (!strcmp(str, \"top-right\"))\n      return LAYER_POSITION_TOP_RIGHT;\n   if (!strcmp(str, \"middle-left\"))\n      return LAYER_POSITION_MIDDLE_LEFT;\n   if (!strcmp(str, \"middle-right\"))\n      return LAYER_POSITION_MIDDLE_RIGHT;\n   if (!strcmp(str, \"bottom-left\"))\n      return LAYER_POSITION_BOTTOM_LEFT;\n   if (!strcmp(str, \"bottom-right\"))\n      return LAYER_POSITION_BOTTOM_RIGHT;\n   if (!strcmp(str, \"top-center\"))\n      return LAYER_POSITION_TOP_CENTER;\n   if (!strcmp(str, \"bottom-center\"))\n      return LAYER_POSITION_BOTTOM_CENTER;\n   return LAYER_POSITION_TOP_LEFT;\n}\n\nstatic int\nparse_control(const char *str)\n{\n   std::string path(str);\n   size_t npos = path.find(\"%p\");\n   if (npos != std::string::npos)\n      path.replace(npos, 2, std::to_string(getpid()));\n   SPDLOG_DEBUG(\"Socket: {}\", path);\n\n   int ret = os_socket_listen_abstract(path.c_str(), 1);\n   if (ret < 0) {\n      SPDLOG_DEBUG(\"Couldn't create socket pipe at '{}'\", path);\n      SPDLOG_DEBUG(\"ERROR: '{}'\", strerror(errno));\n      return ret;\n   }\n\n   os_socket_block(ret, false);\n\n   return ret;\n}\n\nstatic float\nparse_float(const char *str)\n{\n   float val = 0;\n   std::stringstream ss(str);\n   ss.imbue(std::locale::classic());\n   ss >> val;\n   return val;\n}\n\n#if defined(HAVE_X11) || defined(HAVE_WAYLAND)\nstatic std::vector<KeySym>\nparse_string_to_keysym_vec(const char *str)\n{\n   std::vector<KeySym> keys;\n   auto keyStrings = str_tokenize(str);\n   for (auto& ks : keyStrings) {\n      trim(ks);\n      xkb_keysym_t xk = xkb_keysym_from_name(ks.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);\n      if (xk != XKB_KEY_NoSymbol)\n         keys.push_back(xk);\n      else\n         SPDLOG_ERROR(\"Unrecognized key: '{}'\", ks);\n   }\n   return keys;\n}\n\n#define parse_toggle_hud            parse_string_to_keysym_vec\n#define parse_toggle_hud_position   parse_string_to_keysym_vec\n#define parse_toggle_logging        parse_string_to_keysym_vec\n#define parse_reload_cfg            parse_string_to_keysym_vec\n#define parse_upload_log            parse_string_to_keysym_vec\n#define parse_upload_logs           parse_string_to_keysym_vec\n#define parse_toggle_fps_limit      parse_string_to_keysym_vec\n#define parse_toggle_preset         parse_string_to_keysym_vec\n#define parse_reset_fps_metrics     parse_string_to_keysym_vec\n\n#else\n#define parse_toggle_hud(x)            {}\n#define parse_toggle_hud_position(x)   {}\n#define parse_toggle_logging(x)        {}\n#define parse_reload_cfg(x)            {}\n#define parse_upload_log(x)            {}\n#define parse_upload_logs(x)           {}\n#define parse_toggle_fps_limit(x)      {}\n#define parse_toggle_preset(x)         {}\n#define parse_reset_fps_metrics(x)     {}\n#endif\n\n// NOTE: This is NOT defined as an OVERLAY_PARAM and will be called manually\nstatic std::vector<int>\nparse_preset(const char *str)\n{\n  std::vector<int> presets;\n  auto preset_strings = str_tokenize(str);\n\n  for (auto& value : preset_strings) {\n    trim(value);\n\n    uint32_t as_int;\n    try {\n      as_int = static_cast<int>(std::stoi(value));\n    } catch (const std::invalid_argument&) {\n      SPDLOG_ERROR(\"invalid preset value: '{}'\", value);\n      continue;\n    }\n\n    presets.push_back(as_int);\n  }\n\n  return presets;\n}\n\nstatic std::map<std::string, std::string> parse_cpu_custom_temp_sensor(const std::string str) {\n   size_t pos = str.find(\",\");\n   std::map<std::string, std::string> map;\n\n   if (pos != std::string::npos && pos != str.length() - 1) {\n      map[\"hwmon_name\"] = str.substr(0, pos);\n      map[\"hwmon_input\"] = str.substr(pos + 1);\n   }\n\n   SPDLOG_DEBUG(\n      \"cpu_custom_temp_sensor: name=\\\"{}\\\" input=\\\"{}\\\"\",\n      map[\"hwmon_name\"],\n      map[\"hwmon_input\"]\n   );\n\n   return map;\n}\n\nstatic uint32_t\nparse_fps_sampling_period(const char *str)\n{\n   return strtol(str, NULL, 0) * 1000000; /* ms to ns */\n}\n\nstatic std::vector<float>\nparse_fps_limit(const char *str)\n{\n   std::vector<float> fps_limit;\n   auto fps_limit_strings = str_tokenize(str);\n\n   for (auto& value : fps_limit_strings) {\n      trim(value);\n\n      float as_float;\n      try {\n         as_float = std::stof(value);\n      } catch (const std::invalid_argument&) {\n         SPDLOG_ERROR(\"invalid fps_limit value: '{}'\", value);\n         continue;\n      } catch (const std::out_of_range&) {\n         SPDLOG_ERROR(\"fps_limit value out of range: '{}'\", value);\n         continue;\n      }\n\n      fps_limit.push_back(as_float);\n   }\n\n   return fps_limit;\n}\n\nstatic enum fps_limit_method\nparse_fps_limit_method(const char *str)\n{\n   if (!strcmp(str, \"early\")) {\n      return FPS_LIMIT_METHOD_EARLY;\n   }\n\n   return FPS_LIMIT_METHOD_LATE;\n}\n\nstatic bool\nparse_no_display(const char *str)\n{\n   return strtol(str, NULL, 0) != 0;\n}\n\nstatic unsigned\nparse_color(const char *str)\n{\n   return strtol(str, NULL, 16);\n}\n\nstatic std::vector<unsigned>\nparse_load_color(const char *str)\n{\n   std::vector<unsigned> load_colors;\n   auto tokens = str_tokenize(str);\n   std::string token;\n\n   for (auto& token : tokens) {\n      trim(token);\n      load_colors.push_back(std::stoi(token, NULL, 16));\n   }\n\n   // pad vec with white color so we always have at least 3\n   while (load_colors.size() < 3) {\n      load_colors.push_back(std::stoi(\"FFFFFF\" , NULL, 16));\n   }\n\n    return load_colors;\n}\n\nstatic std::vector<unsigned>\nparse_load_value(const char *str)\n{\n   std::vector<unsigned> load_value;\n   auto tokens = str_tokenize(str);\n   std::string token;\n   for (auto& token : tokens) {\n      trim(token);\n      load_value.push_back(std::stoi(token));\n   }\n    return load_value;\n}\n\n\nstatic std::vector<std::string>\nparse_str_tokenize(const char *str, const std::string& delims = \",:+\", bool btrim = true)\n{\n   std::vector<std::string> data;\n   auto tokens = str_tokenize(str, delims);\n   std::string token;\n   for (auto& token : tokens) {\n      if (btrim)\n         trim(token);\n      data.push_back(token);\n   }\n    return data;\n}\n\nstatic std::vector<unsigned>\nparse_gpu_list(const char *str) {\n\n   std::vector<unsigned int> result;\n   auto gpu_list_strings = str_tokenize(str);\n\n   for (auto& value : gpu_list_strings) {\n      trim(value);\n\n      unsigned int num = stoul(value);\n      result.push_back(num);\n   }\n\n   return result;\n}\n\n\nstatic unsigned\nparse_unsigned(const char *str)\n{\n   return strtol(str, NULL, 0);\n}\n\nstatic signed\nparse_signed(const char *str)\n{\n   return strtol(str, NULL, 0);\n}\n\nstatic std::string\nparse_str(const char *str)\n{\n   return str;\n}\n\nstatic std::string\nparse_path(const char *str)\n{\n#ifdef _XOPEN_SOURCE\n   // Expand ~/ to home dir\n   if (str[0] == '~') {\n      std::stringstream s;\n      wordexp_t e;\n      int ret;\n\n      if (!(ret = wordexp(str, &e, 0))) {\n         for(size_t i = 0; i < e.we_wordc; i++)\n         {\n            if (i > 0)\n               s << \" \";\n            s << e.we_wordv[i];\n         }\n      }\n      wordfree(&e);\n\n      if (!ret)\n         return s.str();\n   }\n#endif\n   return str;\n}\n\nstatic std::vector<std::string>\nparse_benchmark_percentiles(const char *str)\n{\n   SPDLOG_INFO(\"benchmark_percetile is obsolete and will be removed. Use fps_metrics instead\");\n   std::vector<std::string> percentiles;\n   return percentiles;\n}\n\nstatic uint32_t\nparse_font_glyph_ranges(const char *str)\n{\n   uint32_t fg = 0;\n   auto tokens = str_tokenize(str);\n   for (auto& token : tokens) {\n      trim(token);\n      std::transform(token.begin(), token.end(), token.begin(), ::tolower);\n\n      if (token == \"korean\")\n         fg |= FG_KOREAN;\n      else if (token == \"chinese\")\n         fg |= FG_CHINESE_FULL;\n      else if (token == \"chinese_simplified\")\n         fg |= FG_CHINESE_SIMPLIFIED;\n      else if (token == \"japanese\")\n         fg |= FG_JAPANESE;\n      else if (token == \"cyrillic\")\n         fg |= FG_CYRILLIC;\n      else if (token == \"thai\")\n         fg |= FG_THAI;\n      else if (token == \"vietnamese\")\n         fg |= FG_VIETNAMESE;\n      else if (token == \"latin_ext_a\")\n         fg |= FG_LATIN_EXT_A;\n      else if (token == \"latin_ext_b\")\n         fg |= FG_LATIN_EXT_B;\n   }\n   return fg;\n}\n\nstatic gl_size_query\nparse_gl_size_query(const char *str)\n{\n   std::string value(str);\n   trim(value);\n   std::transform(value.begin(), value.end(), value.begin(), ::tolower);\n   if (value == \"viewport\")\n      return GL_SIZE_VIEWPORT;\n   if (value == \"scissorbox\")\n      return GL_SIZE_SCISSORBOX;\n   return GL_SIZE_DRAWABLE;\n}\n\nstatic std::vector<std::string>\nparse_fps_metrics(const char *str){\n   std::vector<std::string> metrics;\n   auto tokens = str_tokenize(str);\n   for (auto& token : tokens) {\n      metrics.push_back(token);\n   }\n\n   fpsmetrics = std::make_unique<fpsMetrics>(metrics);\n   return metrics;\n}\n\nstatic overlay_params::fex_stats_options\nparse_fex_stats(const char *str) {\n   overlay_params::fex_stats_options options {\n#ifdef HAVE_FEX\n      .enabled = fex::is_fex_capable(),\n#endif\n   };\n\n   auto tokens = str_tokenize(str);\n#define option_check(str, option) do { \\\n      if (token == #str) options.option = true; \\\n   } while (0)\n\n   // If we have any tokens then default disable.\n   if (!tokens.empty()) {\n      options.status = false;\n      options.app_type = false;\n      options.hot_threads = false;\n      options.jit_load = false;\n      options.sigbus_counts = false;\n      options.smc_counts = false;\n      options.softfloat_counts = false;\n   }\n\n   for (auto& token : tokens) {\n      option_check(status, status);\n      option_check(apptype, app_type);\n      option_check(hotthreads, hot_threads);\n      option_check(jitload, jit_load);\n      option_check(sigbus, sigbus_counts);\n      option_check(smc, smc_counts);\n      option_check(softfloat, softfloat_counts);\n   }\n\n   return options;\n}\n\nstatic overlay_params::ftrace_options\nparse_ftrace(const char *str) {\n   overlay_params::ftrace_options options;\n#ifdef HAVE_FTRACE\n   auto ftrace_params = str_tokenize(str, \"+\");\n   for (auto& param : ftrace_params) {\n      auto tokenized_param = str_tokenize(param, \"/\");\n      if (tokenized_param.empty()) {\n         SPDLOG_ERROR(\"Failed to parse ftrace parameter '{}'\", param);\n         continue;\n      }\n\n      if (tokenized_param[0] == \"histogram\") {\n         if (tokenized_param.size() != 2) {\n            SPDLOG_ERROR(\"Failed to parse ftrace histogram parameter '{}'\", param);\n            continue;\n         }\n\n         SPDLOG_DEBUG(\"Using ftrace histogram for '{}'\", tokenized_param[1]);\n         options.tracepoints.push_back(std::make_shared<FTrace::Tracepoint>(\n            FTrace::Tracepoint {\n               .name = tokenized_param[1],\n               .type = FTrace::TracepointType::Histogram,\n            }));\n      } else if (tokenized_param[0] == \"linegraph\") {\n         if (tokenized_param.size() != 3) {\n            SPDLOG_ERROR(\"Failed to parse ftrace linegraph parameter '{}'\", param);\n            continue;\n         }\n\n         SPDLOG_DEBUG(\"Using ftrace line graph for '{}'\", tokenized_param[1]);\n         options.tracepoints.push_back(std::make_shared<FTrace::Tracepoint>(\n            FTrace::Tracepoint {\n               .name = tokenized_param[1],\n               .type = FTrace::TracepointType::LineGraph,\n               .field_name = tokenized_param[2],\n            }));\n      } else if (tokenized_param[0] == \"label\") {\n         if (tokenized_param.size() != 3) {\n            SPDLOG_ERROR(\"Failed to parse ftrace label parameter '{}'\", param);\n            continue;\n         }\n\n         SPDLOG_DEBUG(\"Using ftrace label for '{}', label name '{}'\", tokenized_param[1], tokenized_param[2]);\n         options.tracepoints.push_back(std::make_shared<FTrace::Tracepoint>(\n            FTrace::Tracepoint {\n               .name = tokenized_param[1],\n               .type = FTrace::TracepointType::Label,\n               .field_name = tokenized_param[2],\n            }));\n      } else {\n         SPDLOG_ERROR(\"Failed to parse ftrace parameter '{}'\", param);\n      }\n   }\n\n   options.enabled = !options.tracepoints.empty();\n#endif // HAVE_FTRACE\n   return options;\n}\n\n#define parse_width(s) parse_unsigned(s)\n#define parse_height(s) parse_unsigned(s)\n#define parse_vulkan_present_mode(s) parse_str(s)\n#define parse_vsync(s) parse_unsigned(s)\n#define parse_gl_vsync(s) parse_signed(s)\n#define parse_offset_x(s) parse_unsigned(s)\n#define parse_offset_y(s) parse_unsigned(s)\n#define parse_log_duration(s) parse_unsigned(s)\n#define parse_time_format(s) parse_str(s)\n#define parse_output_folder(s) parse_path(s)\n#define parse_output_file(s) parse_path(s)\n#define parse_font_file(s) parse_path(s)\n#define parse_font_file_text(s) parse_path(s)\n#define parse_io_read(s) parse_unsigned(s)\n#define parse_io_write(s) parse_unsigned(s)\n#define parse_pci_dev(s) parse_str(s)\n#define parse_media_player_name(s) parse_str(s)\n#define parse_font_scale_media_player(s) parse_float(s)\n#define parse_cpu_text(s) parse_str(s)\n#define parse_fps_text(s) parse_str(s)\n#define parse_log_interval(s) parse_unsigned(s)\n#define parse_font_size(s) parse_float(s)\n#define parse_font_size_secondary(s) parse_float(s)\n#define parse_font_size_text(s) parse_float(s)\n#define parse_font_scale(s) parse_float(s)\n#define parse_background_alpha(s) parse_float(s)\n#define parse_alpha(s) parse_float(s)\n#define parse_permit_upload(s) parse_unsigned(s)\n#define parse_no_small_font(s) parse_unsigned(s) != 0\n#define parse_cellpadding_y(s) parse_float(s)\n#define parse_table_columns(s) parse_unsigned(s)\n#define parse_autostart_log(s) parse_unsigned(s)\n#define parse_gl_bind_framebuffer(s) parse_unsigned(s)\n#define parse_gl_dont_flip(s) parse_unsigned(s) != 0\n#define parse_round_corners(s) parse_unsigned(s)\n#define parse_fcat_overlay_width(s) parse_unsigned(s)\n#define parse_fcat_screen_edge(s) parse_unsigned(s)\n#define parse_picmip(s) parse_signed(s)\n#define parse_af(s) parse_signed(s)\n\n#define parse_cpu_color(s) parse_color(s)\n#define parse_gpu_color(s) parse_color(s)\n#define parse_vram_color(s) parse_color(s)\n#define parse_ram_color(s) parse_color(s)\n#define parse_engine_color(s) parse_color(s)\n#define parse_io_color(s) parse_color(s)\n#define parse_frametime_color(s) parse_color(s)\n#define parse_background_color(s) parse_color(s)\n#define parse_text_color(s) parse_color(s)\n#define parse_media_player_color(s) parse_color(s)\n#define parse_wine_color(s) parse_color(s)\n#define parse_horizontal_separator_color(s) parse_color(s)\n#define parse_network_color(s) parse_color(s)\n#define parse_gpu_load_color(s) parse_load_color(s)\n#define parse_cpu_load_color(s) parse_load_color(s)\n#define parse_gpu_load_value(s) parse_load_value(s)\n#define parse_cpu_load_value(s) parse_load_value(s)\n#define parse_blacklist(s) parse_str_tokenize(s)\n#define parse_custom_text_center(s) parse_str(s)\n#define parse_custom_text(s) parse_str(s)\n#define parse_fps_value(s) parse_load_value(s)\n#define parse_fps_color(s) parse_load_color(s)\n#define parse_battery_color(s) parse_color(s)\n#define parse_media_player_format(s) parse_str_tokenize(s, \";\", false)\n#define parse_fsr_steam_sharpness(s) parse_float(s)\n#define parse_text_outline_color(s) parse_color(s)\n#define parse_text_outline_thickness(s) parse_float(s)\n#define parse_device_battery(s) parse_str_tokenize(s)\n#define parse_network(s) parse_str_tokenize(s)\n#define parse_gpu_text(s) parse_str_tokenize(s)\n\nstatic bool\nparse_help(const char *str)\n{\n   fprintf(stderr, \"Layer params using MANGOHUD_CONFIG=\\n\");\n#define OVERLAY_PARAM_BOOL(name)                \\\n   fprintf(stderr, \"\\t%s=0|1\\n\", #name);\n#define OVERLAY_PARAM_CUSTOM(name)\n   OVERLAY_PARAMS\n#undef OVERLAY_PARAM_BOOL\n#undef OVERLAY_PARAM_CUSTOM\n   fprintf(stderr, \"\\tposition=top-left|top-right|bottom-left|bottom-right\\n\");\n   fprintf(stderr, \"\\tfps_sampling_period=number-of-milliseconds\\n\");\n   fprintf(stderr, \"\\tno_display=0|1\\n\");\n   fprintf(stderr, \"\\toutput_folder=/path/to/folder\\n\");\n   fprintf(stderr, \"\\twidth=width-in-pixels\\n\");\n   fprintf(stderr, \"\\theight=height-in-pixels\\n\");\n\n   return true;\n}\n\nstatic bool is_delimiter(char c)\n{\n   return c == 0 || c == ',' || c == ':' || c == ';' || c == '=';\n}\n\nstatic int\nparse_string(const char *s, char *out_param, char *out_value)\n{\n   int i = 0;\n\n   for (; !is_delimiter(*s); s++, out_param++, i++)\n      *out_param = *s;\n\n   *out_param = 0;\n\n   if (*s == '=') {\n      s++;\n      i++;\n      for (; !is_delimiter(*s); s++, out_value++, i++) {\n         *out_value = *s;\n         // Consume escaped delimiter, but don't escape null. Might be end of string.\n         if (*s == '\\\\' && *(s + 1) != 0 && is_delimiter(*(s + 1))) {\n            s++;\n            i++;\n            *out_value = *s;\n         }\n      }\n   } else\n      *(out_value++) = '1';\n   *out_value = 0;\n\n   if (*s && is_delimiter(*s)) {\n      s++;\n      i++;\n   }\n\n   if (*s && !i) {\n      SPDLOG_ERROR(\"syntax error: unexpected '{0:c}' ({0:d}) while \"\n              \"parsing a string\", *s);\n   }\n\n   return i;\n}\n\nconst char *overlay_param_names[] = {\n#define OVERLAY_PARAM_BOOL(name) #name,\n#define OVERLAY_PARAM_CUSTOM(name)\n   OVERLAY_PARAMS\n#undef OVERLAY_PARAM_BOOL\n#undef OVERLAY_PARAM_CUSTOM\n};\n\nstatic void\ninitialize_preset(struct overlay_params *params)\n{\n   if (params->options.find(\"preset\") != params->options.end()) {\n      auto presets = parse_preset(params->options.find(\"preset\")->second.c_str());\n      if (!presets.empty())\n         params->preset = presets;\n   }\n   current_preset = params->preset[0];\n}\n\nstatic void\nset_parameters_from_options(struct overlay_params *params)\n{\n   bool read_cfg = false;\n   if (params->options.find(\"read_cfg\") != params->options.end() && params->options.find(\"read_cfg\")->second != \"0\")\n      read_cfg = true;\n\n   if (params->options.find(\"full\") != params->options.end() && params->options.find(\"full\")->second != \"0\") {\n#define OVERLAY_PARAM_BOOL(name) \\\n      params->enabled[OVERLAY_PARAM_ENABLED_##name] = 1;\n#define OVERLAY_PARAM_CUSTOM(name)\n      OVERLAY_PARAMS\n      #undef OVERLAY_PARAM_BOOL\n      #undef OVERLAY_PARAM_CUSTOM\n      params->enabled[OVERLAY_PARAM_ENABLED_histogram] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_battery_icon] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_fcat] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_horizontal] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_log_versioning] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_exec_name] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_trilinear] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_bicubic] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_retro] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_debug] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_hide_engine_names] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = 0;\n      params->enabled[OVERLAY_PARAM_ENABLED_duration] = false;\n      params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false;\n      params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = read_cfg;\n      params->enabled[OVERLAY_PARAM_ENABLED_time_no_label] = false;\n      params->enabled[OVERLAY_PARAM_ENABLED_core_type] = false;\n      params->options.erase(\"full\");\n   }\n   for (auto& it : params->options) {\n#define OVERLAY_PARAM_BOOL(name)                                 \\\n      if (it.first == #name) {                                   \\\n          params->enabled[OVERLAY_PARAM_ENABLED_##name] =        \\\n          strtol(it.second.c_str(), NULL, 0);                    \\\n          continue;                                              \\\n       }\n#define OVERLAY_PARAM_CUSTOM(name)                               \\\n      if (it.first == #name) {                                   \\\n         params->name = parse_##name(it.second.c_str());         \\\n      continue;                                                  \\\n   }\n      OVERLAY_PARAMS\n      #undef OVERLAY_PARAM_BOOL\n      #undef OVERLAY_PARAM_CUSTOM\n      if (it.first == \"preset\") {\n         continue; // Handled above\n      }\n      SPDLOG_ERROR(\"Unknown option '{}'\", it.first.c_str());\n   }\n}\n\nstatic void\nparse_overlay_env(struct overlay_params *params,\n                  const char *env, bool use_existing_preset)\n{\n   const char *env_start = env;\n\n   uint32_t num;\n   char key[256], value[256];\n   while ((num = parse_string(env, key, value)) != 0) {\n      trim_char(key);\n      trim_char(value);\n      env += num;\n      if (!strcmp(\"preset\", key)) {\n         if (!use_existing_preset) {\n            add_to_options(params, key, value);\n            initialize_preset(params);\n         }\n         break;\n      }\n   }\n\n   presets(current_preset, params);\n   env = env_start;\n\n   while ((num = parse_string(env, key, value)) != 0) {\n      trim_char(key);\n      trim_char(value);\n      env += num;\n      if (!strcmp(\"preset\", key)) {\n         continue; // Avoid 'Unknown option' error\n      }\n#define OVERLAY_PARAM_BOOL(name)                                       \\\n      if (!strcmp(#name, key)) {                                       \\\n         add_to_options(params, key, value);                           \\\n         continue;                                                     \\\n      }\n#define OVERLAY_PARAM_CUSTOM(name)                                     \\\n      if (!strcmp(#name, key)) {                                       \\\n         add_to_options(params, key, value);                           \\\n         continue;                                                     \\\n      }\n      OVERLAY_PARAMS\n#undef OVERLAY_PARAM_BOOL\n#undef OVERLAY_PARAM_CUSTOM\n      SPDLOG_ERROR(\"Unknown option '{}'\", key);\n   }\n   set_parameters_from_options(params);\n}\n\nstatic void set_param_defaults(struct overlay_params *params){\n   params->enabled[OVERLAY_PARAM_ENABLED_fps] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_frame_timing] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_core_load] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_cpu_power] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_junction_temp] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_ram] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_ram_temp] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_swap] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_vram] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_io_read] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_io_write] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_wine] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_load_change] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_cpu_load_change] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_core_load_change] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_gpu_voltage] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_frametime] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_fcat] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_hide_engine_names] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_text_outline] = true;\n   params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_duration] = false;\n   params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed] = false;\n   params->fps_sampling_period = 500000000; /* 500ms */\n   params->width = 0;\n   params->height = 140;\n   params->control = -1;\n   params->fps_limit = { 0 };\n   params->fps_limit_method = FPS_LIMIT_METHOD_LATE;\n   params->vsync = -1;\n   params->gl_vsync = -2;\n   params->offset_x = 0;\n   params->offset_y = 0;\n   params->background_alpha = 0.5;\n   params->alpha = 1.0;\n   params->fcat_screen_edge = 0;\n   params->fcat_overlay_width = 24;\n   params->time_format = \"%T\";\n   params->gpu_color = 0x2e9762;\n   params->cpu_color = 0x2e97cb;\n   params->vram_color = 0xad64c1;\n   params->ram_color = 0xc26693;\n   params->engine_color = 0xeb5b5b;\n   params->io_color = 0xa491d3;\n   params->frametime_color = 0x00ff00;\n   params->background_color = 0x020202;\n   params->text_color = 0xffffff;\n   params->media_player_color = 0xffffff;\n   params->network_color = 0xe07b85;\n   params->media_player_name = \"\";\n   params->font_scale = 1.0f;\n   params->wine_color = 0xeb5b5b;\n   params->horizontal_separator_color = 0xad64c1;\n   params->gpu_load_color = { 0x39f900, 0xfdfd09, 0xb22222 };\n   params->cpu_load_color = { 0x39f900, 0xfdfd09, 0xb22222 };\n   params->font_scale_media_player = 0.55f;\n   params->log_interval = 0;\n   params->media_player_format = { \"{title}\", \"{artist}\", \"{album}\" };\n   params->permit_upload = 0;\n   params->benchmark_percentiles = { \"97\", \"AVG\"};\n   params->gpu_load_value = { 60, 90 };\n   params->cpu_load_value = { 60, 90 };\n   params->cellpadding_y = -0.085;\n   params->fps_color = { 0xb22222, 0xfdfd09, 0x39f900 };\n   params->fps_value = { 30, 60 };\n   params->round_corners = 0;\n   params->battery_color =0xff9078;\n   params->fsr_steam_sharpness = -1;\n   params->picmip = -17;\n   params->af = -1;\n   params->font_size = 24;\n   params->table_columns = 3;\n   params->text_outline_color = 0x000000;\n   params->text_outline_thickness = 1.5;\n}\n\nstatic std::string verify_pci_dev(std::string pci_dev) {\n   uint32_t domain, bus, slot, func;\n\n   if (\n      sscanf(\n         pci_dev.c_str(), \"%04x:%02x:%02x.%x\",\n         &domain, &bus, &slot, &func\n      ) != 4) {\n      SPDLOG_ERROR(\"Failed to parse PCI device ID: '{}'\", pci_dev);\n      return pci_dev;\n   }\n\n   std::stringstream ss;\n   ss << std::hex\n      << std::setw(4) << std::setfill('0') << domain << \":\"\n      << std::setw(2) << bus << \":\"\n      << std::setw(2) << slot << \".\"\n      << std::setw(1) << func;\n\n   SPDLOG_DEBUG(\"pci_dev = {}\", ss.str());\n   return ss.str();\n}\n\nvoid\nparse_overlay_config(struct overlay_params *params,\n                  const char *env, bool use_existing_preset)\n{\n   SPDLOG_DEBUG(\"Version: {}\", MANGOHUD_VERSION);\n   std::vector<int> default_preset = {-1, 0, 1, 2, 3, 4};\n   auto preset = std::move(params->preset);\n   int transfer_function = params->transfer_function;\n   *params = {};\n   params->transfer_function = transfer_function;\n   params->preset = use_existing_preset ? std::move(preset) : default_preset;\n   set_param_defaults(params);\n   if (!use_existing_preset) {\n      current_preset = params->preset[0];\n   }\n\n#if defined(HAVE_X11) || defined(HAVE_WAYLAND)\n   params->toggle_hud = { XKB_KEY_Shift_R, XKB_KEY_F12 };\n   params->toggle_hud_position = { XKB_KEY_Shift_R, XKB_KEY_F11 };\n   params->toggle_preset = { XKB_KEY_Shift_R, XKB_KEY_F10 };\n   params->reset_fps_metrics = { XKB_KEY_Shift_R, XKB_KEY_F9};\n   params->toggle_fps_limit = { XKB_KEY_Shift_L, XKB_KEY_F1 };\n   params->toggle_logging = { XKB_KEY_Shift_L, XKB_KEY_F2 };\n   params->reload_cfg = { XKB_KEY_Shift_L, XKB_KEY_F4 };\n   params->upload_log = { XKB_KEY_Shift_L, XKB_KEY_F3 };\n   params->upload_logs = { XKB_KEY_Control_L, XKB_KEY_F3 };\n#endif\n\n#ifdef _WIN32\n   params->toggle_hud = { VK_F12 };\n   params->toggle_preset = { VK_F10 };\n   params->reset_fps_metrics = { VK_F9};\n   params->toggle_fps_limit = { VK_F3 };\n   params->toggle_logging = { VK_F2 };\n   params->reload_cfg = { VK_F4 };\n\n   #undef parse_toggle_hud\n   #undef parse_toggle_fps_limit\n   #undef parse_toggle_preset\n   #undef parse_toggle_logging\n   #undef parse_reload_cfg\n\n   #define parse_toggle_hud(x)         params->toggle_hud\n   #define parse_toggle_preset(x)      params->toggle_preset\n   #define parse_toggle_fps_limit(x)   params->toggle_fps_limit\n   #define parse_toggle_logging(x)     params->toggle_logging\n   #define parse_reload_cfg(x)         params->reload_cfg\n#endif\n\n   HUDElements.ordered_functions.clear();\n   HUDElements.exec_list.clear();\n   params->options.clear();\n   HUDElements.options.clear();\n\n   // first pass with env var\n   if (env)\n      parse_overlay_env(params, env, use_existing_preset);\n\n   bool read_cfg = params->enabled[OVERLAY_PARAM_ENABLED_read_cfg];\n   bool env_contains_preset = params->options.find(\"preset\") != params->options.end();\n\n   if (!env || read_cfg) {\n      parseConfigFile(*params);\n\n      if (!use_existing_preset && !env_contains_preset) {\n         initialize_preset(params);\n      }\n\n      // clear options since we don't want config options to appear first\n      params->options.clear();\n      HUDElements.options.clear();\n      // add preset options\n      presets(current_preset, params);\n      // potentially override preset options with config options\n      parseConfigFile(*params);\n\n      set_parameters_from_options(params);\n   }\n\n   if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout])\n      HUDElements.ordered_functions.clear();\n\n   if (env && read_cfg) {\n      HUDElements.ordered_functions.clear();\n      parse_overlay_env(params, env, true);\n   }\n\n   // If fps_only param is enabled disable legacy_layout\n   if (params->enabled[OVERLAY_PARAM_ENABLED_fps_only])\n      params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = false;\n\n   if (is_blacklisted())\n      return;\n\n   if (params->font_scale_media_player <= 0.f)\n      params->font_scale_media_player = 0.55f;\n\n   // Convert from 0xRRGGBB to ImGui's format\n   std::array<unsigned *, 24> colors = {\n      &params->cpu_color,\n      &params->gpu_color,\n      &params->vram_color,\n      &params->ram_color,\n      &params->engine_color,\n      &params->io_color,\n      &params->background_color,\n      &params->frametime_color,\n      &params->text_color,\n      &params->media_player_color,\n      &params->wine_color,\n      &params->horizontal_separator_color,\n      &params->battery_color,\n      &params->gpu_load_color[0],\n      &params->gpu_load_color[1],\n      &params->gpu_load_color[2],\n      &params->cpu_load_color[0],\n      &params->cpu_load_color[1],\n      &params->cpu_load_color[2],\n      &params->fps_color[0],\n      &params->fps_color[1],\n      &params->fps_color[2],\n      &params->text_outline_color,\n      &params->network_color,\n   };\n\n   for (auto color : colors){\n      *color =\n      IM_COL32(RGBGetRValue(*color),\n               RGBGetGValue(*color),\n               RGBGetBValue(*color),\n               255);\n   }\n\n   params->table_columns = std::max(1u, std::min(64u, params->table_columns));\n\n   //increase hud width if io read and write\n   if (!params->width && !params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) {\n      params->width = params->font_size * params->font_scale * params->table_columns * 4.6;\n\n      if ((params->enabled[OVERLAY_PARAM_ENABLED_io_read] || params->enabled[OVERLAY_PARAM_ENABLED_io_write])) {\n         params->width += 2 * params->font_size * params->font_scale;\n      }\n\n      // Treat it like hud would need to be ~7 characters wider with default font.\n      if (params->no_small_font)\n         params->width += 7 * params->font_size * params->font_scale;\n   }\n\n   // If secondary font size not set, compute it from main font_size\n   if (!params->font_size_secondary) {\n      float coeff = params->no_small_font ? 1 : 0.55;\n      params->font_size_secondary = params->font_size * coeff;\n   }\n\n   params->font_params_hash = get_hash(params->font_size,\n                                 params->font_size_text,\n                                 params->no_small_font,\n                                 params->font_file,\n                                 params->font_file_text,\n                                 params->font_glyph_ranges,\n                                 params->font_scale,\n                                 params->font_size_secondary\n                                );\n\n   // check if user specified an env for fps limiter instead\n   const char *fps_limit_env = getenv(\"MANGOHUD_FPS_LIMIT\");\n   if (fps_limit_env)\n   {\n      try {\n         int fps = std::stof(fps_limit_env);\n         auto front = params->fps_limit.begin();\n         params->fps_limit.insert(front, fps);\n      } catch(...) {}\n   }\n\n#ifdef HAVE_DBUS\n   if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) {\n      if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_MPRIS))\n         dbusmgr::dbus_mgr.init_mpris(params->media_player_name);\n   } else {\n      dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_MPRIS);\n      main_metadata.meta.valid = false;\n   }\n\n   // if (params->enabled[OVERLAY_PARAM_ENABLED_gamemode])\n   // {\n   //    if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_GAMEMODE))\n   //       HUDElements.gamemode_bol = dbusmgr::dbus_mgr.gamemode_enabled(getpid());\n   // }\n   // else\n   //    dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_GAMEMODE);\n\n#endif\n\n   if(!params->output_file.empty()) {\n      SPDLOG_INFO(\"output_file is deprecated, use output_folder instead\");\n   }\n\n   auto real_size = params->font_size * params->font_scale;\n   real_font_size = ImVec2(real_size, real_size / 2);\n\n   for (const auto& option : HUDElements.options) {\n      SPDLOG_DEBUG(\"Param: '{}' = '{}'\", option.first, option.second);\n   }\n\n   // Needs ImGui context but it is null here for OpenGL so just note it and update somewhere else\n   HUDElements.colors.update = true;\n   if (params->no_small_font)\n      HUDElements.text_column = 2;\n   else\n      HUDElements.text_column = 1;\n\n   if(logger && logger->is_active()){\n      SPDLOG_DEBUG(\"Stopped logging because config reloaded\");\n      logger->stop_logging();\n   }\n   logger = std::make_unique<Logger>(params);\n#ifdef MANGOAPP\n   {\n      extern bool new_frame;\n      std::lock_guard<std::mutex> lk(mangoapp_m);\n      params->no_display = params->no_display;\n      new_frame = true; // we probably changed how we look.\n   }\n   mangoapp_cv.notify_one();\n   g_fsrSharpness = params->fsr_steam_sharpness;\n#endif\n   if (HUDElements.net)\n      HUDElements.net->should_reset = true;\n\n   // If both options are specified, GPUS::selected_gpus() is going\n   // to return only GPUs listed in gpu_list\n   if (!params->gpu_list.empty() && !params->pci_dev.empty()) {\n      SPDLOG_WARN(\n         \"You have specified both gpu_list and pci_dev, \"\n         \"ignoring pci_dev.\"\n      );\n   }\n\n   if (!params->pci_dev.empty())\n      params->pci_dev = verify_pci_dev(params->pci_dev);\n\n   if (!params->vulkan_present_mode.empty()) {\n      VkPresentModeKHR present_mode;\n      if (parse_vulkan_present_mode_name(params->vulkan_present_mode, present_mode)) {\n         params->m_vulkan_present_mode = present_mode;\n      }\n   } else if ((int)params->vsync != -1) {\n      if (params->vsync < HUDElements.presentModes.size()) {\n         params->m_vulkan_present_mode = HUDElements.presentModes[params->vsync];\n      } else {\n         SPDLOG_WARN(\"vsync={} out of range for [0 .. {}] (ignoring)\", params->vsync, HUDElements.presentModes.size() - 1);\n      }\n   }\n\n   {\n      std::lock_guard<std::mutex> lock(config_mtx);\n      config_ready = true;\n      config_cv.notify_one();\n   }\n\n   auto snapshot = std::make_shared<overlay_params>(*params);\n   std::atomic_store_explicit(&g_params, std::move(snapshot), std::memory_order_release);\n\n   fps_limiter = std::make_unique<fpsLimiter>(params->fps_limit_method ? false : true);\n\n   if (!gpus)\n      gpus = std::make_unique<GPUS>();\n\n   if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout]) {\n      HUDElements.legacy_elements(get_params().get());\n   } else {\n      HUDElements.ordered_functions.clear();\n      for (auto& option : HUDElements.options) {\n         HUDElements.sort_elements(option);\n      }\n   }\n}\n\nstd::shared_ptr<overlay_params> get_params() {\n    for (;;) {\n        auto p = std::atomic_load_explicit(&g_params, std::memory_order_acquire);\n        if (p) return p;\n        std::this_thread::sleep_for(std::chrono::milliseconds(25));\n    }\n}\n\nbool parse_preset_config(int preset, struct overlay_params *params){\n   const char *presets_file_env = getenv(\"MANGOHUD_PRESETSFILE\");\n   const std::string config_dir = get_config_dir();\n   std::string preset_path = presets_file_env ? presets_file_env : config_dir + \"/MangoHud/\" + \"presets.conf\";\n\n   char preset_string[20];\n   snprintf(preset_string, sizeof(preset_string), \"[preset %d]\", preset);\n\n   std::ifstream stream(preset_path);\n   stream.imbue(std::locale::classic());\n\n   if (!stream.good()) {\n      SPDLOG_DEBUG(\"Failed to read presets file: '{}'.  Falling back to default presets\", preset_path);\n      return false;\n   }\n\n   std::string line;\n   bool found_preset = false;\n\n   while (std::getline(stream, line)) {\n      trim(line);\n\n      if (line == \"\")\n         continue;\n\n      if (line == preset_string) {\n         found_preset = true;\n         continue;\n      }\n\n      if (found_preset) {\n         if (line.front() == '[' && line.back() == ']')\n            break;\n\n         if (line == \"inherit\")\n            presets(preset, params, true);\n\n         parseConfigLine(line, params->options);\n      }\n   }\n\n   return found_preset;\n}\n\nvoid add_to_options(struct overlay_params *params, std::string option, std::string value){\n   HUDElements.options.push_back({option, value});\n   params->options[option] = value;\n}\n\nvoid presets(int preset, struct overlay_params *params, bool inherit) {\n   if (!inherit && parse_preset_config(preset, params))\n         return;\n\n   switch(preset) {\n      case 0:\n         params->no_display = 1;\n         break;\n\n      case 1:\n         params->width = 40;\n         add_to_options(params, \"legacy_layout\", \"0\");\n         add_to_options(params, \"cpu_stats\", \"0\");\n         add_to_options(params, \"gpu_stats\", \"0\");\n         add_to_options(params, \"fps\", \"1\");\n         add_to_options(params, \"fps_only\", \"1\");\n         add_to_options(params, \"frametime\", \"0\");\n         add_to_options(params, \"debug\", \"0\");\n         break;\n\n      case 2:\n         params->table_columns = 20;\n         add_to_options(params, \"horizontal\", \"1\");\n         add_to_options(params, \"legacy_layout\", \"0\");\n         add_to_options(params, \"fps\", \"1\");\n         add_to_options(params, \"table_columns\", \"20\");\n         add_to_options(params, \"frame_timing\", \"1\");\n         add_to_options(params, \"frametime\", \"0\");\n         add_to_options(params, \"cpu_stats\", \"1\");\n         add_to_options(params, \"gpu_stats\", \"1\");\n         add_to_options(params, \"ram\", \"1\");\n         add_to_options(params, \"vram\", \"1\");\n         add_to_options(params, \"battery\", \"1\");\n         add_to_options(params, \"hud_no_margin\", \"1\");\n         add_to_options(params, \"gpu_power\", \"1\");\n         add_to_options(params, \"cpu_power\", \"1\");\n         add_to_options(params, \"battery_watt\", \"1\");\n         add_to_options(params, \"battery_time\", \"1\");\n         break;\n\n      case 3:\n         add_to_options(params, \"cpu_temp\", \"1\");\n         add_to_options(params, \"gpu_temp\", \"1\");\n         add_to_options(params, \"ram\", \"1\");\n         add_to_options(params, \"vram\", \"1\");\n         add_to_options(params, \"cpu_power\", \"1\");\n         add_to_options(params, \"gpu_power\", \"1\");\n         add_to_options(params, \"cpu_mhz\", \"1\");\n         add_to_options(params, \"gpu_mem_clock\", \"1\");\n         add_to_options(params, \"gpu_core_clock\", \"1\");\n         add_to_options(params, \"battery\", \"1\");\n         add_to_options(params, \"hdr\", \"1\");\n         add_to_options(params, \"debug\", \"0\");\n         break;\n\n      case 4:\n         add_to_options(params, \"full\", \"1\");\n         add_to_options(params, \"throttling_status\", \"0\");\n         add_to_options(params, \"throttling_status_graph\", \"0\");\n         add_to_options(params, \"io_read\", \"0\");\n         add_to_options(params, \"io_write\", \"0\");\n         add_to_options(params, \"arch\", \"0\");\n         add_to_options(params, \"engine_version\", \"0\");\n         add_to_options(params, \"battery\", \"1\");\n         add_to_options(params, \"gamemode\", \"0\");\n         add_to_options(params, \"vkbasalt\", \"0\");\n         add_to_options(params, \"frame_count\", \"0\");\n         add_to_options(params, \"show_fps_limit\", \"0\");\n         add_to_options(params, \"resolution\", \"0\");\n         add_to_options(params, \"gpu_load_change\", \"0\");\n         add_to_options(params, \"core_load_change\", \"0\");\n         add_to_options(params, \"cpu_load_change\", \"0\");\n         add_to_options(params, \"fps_color_change\", \"0\");\n         add_to_options(params, \"hdr\", \"1\");\n         add_to_options(params, \"refresh_rate\", \"1\");\n         add_to_options(params, \"media_player\", \"0\");\n         add_to_options(params, \"debug\", \"1\");\n         add_to_options(params, \"version\", \"0\");\n         add_to_options(params, \"frame_timing_detailed\", \"1\");\n         add_to_options(params, \"network\", \"1\");\n         add_to_options(params, \"present_mode\", \"0\");\n         add_to_options(params, \"proc_vram\", \"0\");\n         add_to_options(params, \"procmem\", \"0\");\n         add_to_options(params, \"display_server\", \"0\");\n         add_to_options(params, \"gpu_efficiency\", \"0\");\n         add_to_options(params, \"cpu_efficiency\", \"0\");\n\n         // Disable some options if steamdeck / other known handhelds\n         if (!gpus)\n            gpus = std::make_unique<GPUS>(params);\n\n         for (auto gpu : gpus->available_gpus) {\n            if (gpu->device_id == 0x1435 || gpu->device_id == 0x163f || gpu->device_id == 0x1681 || gpu->device_id == 0x15bf){\n               add_to_options(params, \"gpu_fan\", \"0\");\n               add_to_options(params, \"gpu_junction_temp\", \"0\");\n               add_to_options(params, \"gpu_voltage\", \"0\");\n               add_to_options(params, \"gpu_mem_temp\", \"0\");\n               add_to_options(params, \"gpu_efficiency\", \"0\");\n            }\n            // Rembrandt and Phoenix APUs (Z1, Z1E, Z2 Go)\n            if (gpu->device_id == 0x1681 || gpu->device_id == 0x15bf){\n               add_to_options(params, \"gpu_power_limit\", \"0\");\n            }\n         }\n\n         break;\n\n   }\n}\n"
  },
  {
    "path": "src/overlay_params.h",
    "content": "#pragma once\n#ifndef MANGOHUD_OVERLAY_PARAMS_H\n#define MANGOHUD_OVERLAY_PARAMS_H\n\n#include <string>\n#include <vector>\n#include <unordered_map>\n#include <cstdint>\n#include <condition_variable>\n#include <mutex>\n#include <map>\n#include <optional>\n#include <vulkan/vulkan_core.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n#ifndef KeySym\ntypedef unsigned long KeySym;\n#endif\n\n#ifdef HAVE_FTRACE\nnamespace FTrace {\nstruct Tracepoint;\n}\n#endif\n\n#define RGBGetBValue(rgb)   (rgb & 0x000000FF)\n#define RGBGetGValue(rgb)   ((rgb >> 8) & 0x000000FF)\n#define RGBGetRValue(rgb)   ((rgb >> 16) & 0x000000FF)\n\n#define ToRGBColor(r, g, b, a) ((r << 16) | (g << 8) | (b));\n\n#define OVERLAY_PARAMS                               \\\n   OVERLAY_PARAM_BOOL(fps)                           \\\n   OVERLAY_PARAM_BOOL(frame_timing)                  \\\n   OVERLAY_PARAM_BOOL(core_load)                     \\\n   OVERLAY_PARAM_BOOL(core_bars)                     \\\n   OVERLAY_PARAM_BOOL(core_type)                     \\\n   OVERLAY_PARAM_BOOL(cpu_temp)                      \\\n   OVERLAY_PARAM_CUSTOM(cpu_custom_temp_sensor)      \\\n   OVERLAY_PARAM_BOOL(cpu_power)                     \\\n   OVERLAY_PARAM_BOOL(gpu_temp)                      \\\n   OVERLAY_PARAM_BOOL(gpu_junction_temp)             \\\n   OVERLAY_PARAM_BOOL(gpu_mem_temp)                  \\\n   OVERLAY_PARAM_BOOL(cpu_stats)                     \\\n   OVERLAY_PARAM_BOOL(gpu_stats)                     \\\n   OVERLAY_PARAM_BOOL(ram)                           \\\n   OVERLAY_PARAM_BOOL(ram_temp)                      \\\n   OVERLAY_PARAM_BOOL(swap)                          \\\n   OVERLAY_PARAM_BOOL(vram)                          \\\n   OVERLAY_PARAM_BOOL(proc_vram)                     \\\n   OVERLAY_PARAM_BOOL(procmem)                       \\\n   OVERLAY_PARAM_BOOL(procmem_shared)                \\\n   OVERLAY_PARAM_BOOL(procmem_virt)                  \\\n   OVERLAY_PARAM_BOOL(time)                          \\\n   OVERLAY_PARAM_BOOL(full)                          \\\n   OVERLAY_PARAM_BOOL(read_cfg)                      \\\n   OVERLAY_PARAM_BOOL(io_read)                       \\\n   OVERLAY_PARAM_BOOL(io_write)                      \\\n   OVERLAY_PARAM_BOOL(gpu_mem_clock)                 \\\n   OVERLAY_PARAM_BOOL(gpu_core_clock)                \\\n   OVERLAY_PARAM_BOOL(gpu_power)                     \\\n   OVERLAY_PARAM_BOOL(arch)                          \\\n   OVERLAY_PARAM_BOOL(media_player)                  \\\n   OVERLAY_PARAM_BOOL(version)                       \\\n   OVERLAY_PARAM_BOOL(vulkan_driver)                 \\\n   OVERLAY_PARAM_BOOL(gpu_name)                      \\\n   OVERLAY_PARAM_BOOL(engine_version)                \\\n   OVERLAY_PARAM_BOOL(histogram)                     \\\n   OVERLAY_PARAM_BOOL(wine)                          \\\n   OVERLAY_PARAM_BOOL(gpu_load_change)               \\\n   OVERLAY_PARAM_BOOL(cpu_load_change)               \\\n   OVERLAY_PARAM_BOOL(core_load_change)              \\\n   OVERLAY_PARAM_BOOL(graphs)                        \\\n   OVERLAY_PARAM_BOOL(legacy_layout)                 \\\n   OVERLAY_PARAM_BOOL(cpu_mhz)                       \\\n   OVERLAY_PARAM_BOOL(frametime)                     \\\n   OVERLAY_PARAM_BOOL(frame_count)                   \\\n   OVERLAY_PARAM_BOOL(resolution)                    \\\n   OVERLAY_PARAM_BOOL(show_fps_limit)                \\\n   OVERLAY_PARAM_BOOL(fps_color_change)              \\\n   OVERLAY_PARAM_BOOL(custom_text_center)            \\\n   OVERLAY_PARAM_BOOL(custom_text)                   \\\n   OVERLAY_PARAM_BOOL(exec)                          \\\n   OVERLAY_PARAM_BOOL(vkbasalt)                      \\\n   OVERLAY_PARAM_BOOL(gamemode)                      \\\n   OVERLAY_PARAM_BOOL(battery)                       \\\n   OVERLAY_PARAM_BOOL(battery_icon)                  \\\n   OVERLAY_PARAM_BOOL(fps_only)                      \\\n   OVERLAY_PARAM_BOOL(fsr)                           \\\n   OVERLAY_PARAM_BOOL(mangoapp_steam)                \\\n   OVERLAY_PARAM_BOOL(debug)                         \\\n   OVERLAY_PARAM_BOOL(device_battery_icon)           \\\n   OVERLAY_PARAM_BOOL(hide_fsr_sharpness)            \\\n   OVERLAY_PARAM_BOOL(fan)                           \\\n   OVERLAY_PARAM_BOOL(throttling_status)             \\\n   OVERLAY_PARAM_BOOL(throttling_status_graph)       \\\n   OVERLAY_PARAM_BOOL(fcat)                          \\\n   OVERLAY_PARAM_BOOL(log_versioning)                \\\n   OVERLAY_PARAM_BOOL(horizontal)                    \\\n   OVERLAY_PARAM_BOOL(horizontal_stretch)            \\\n   OVERLAY_PARAM_BOOL(hud_no_margin)                 \\\n   OVERLAY_PARAM_BOOL(hud_compact)                   \\\n   OVERLAY_PARAM_BOOL(battery_watt)                  \\\n   OVERLAY_PARAM_BOOL(battery_time)                  \\\n   OVERLAY_PARAM_BOOL(exec_name)                     \\\n   OVERLAY_PARAM_BOOL(trilinear)                     \\\n   OVERLAY_PARAM_BOOL(bicubic)                       \\\n   OVERLAY_PARAM_BOOL(retro)                         \\\n   OVERLAY_PARAM_BOOL(gpu_fan)                       \\\n   OVERLAY_PARAM_BOOL(gpu_voltage)                   \\\n   OVERLAY_PARAM_BOOL(engine_short_names)            \\\n   OVERLAY_PARAM_BOOL(hide_engine_names)             \\\n   OVERLAY_PARAM_BOOL(hide_fps_superscript)          \\\n   OVERLAY_PARAM_BOOL(text_outline)                  \\\n   OVERLAY_PARAM_BOOL(temp_fahrenheit)               \\\n   OVERLAY_PARAM_BOOL(dynamic_frame_timing)          \\\n   OVERLAY_PARAM_BOOL(duration)                      \\\n   OVERLAY_PARAM_BOOL(inherit)                       \\\n   OVERLAY_PARAM_BOOL(hdr)                           \\\n   OVERLAY_PARAM_BOOL(refresh_rate)                  \\\n   OVERLAY_PARAM_BOOL(frame_timing_detailed)         \\\n   OVERLAY_PARAM_BOOL(winesync)                      \\\n   OVERLAY_PARAM_BOOL(present_mode)                  \\\n   OVERLAY_PARAM_BOOL(time_no_label)                 \\\n   OVERLAY_PARAM_BOOL(display_server)                \\\n   OVERLAY_PARAM_BOOL(cpu_efficiency)                \\\n   OVERLAY_PARAM_BOOL(gpu_efficiency)                \\\n   OVERLAY_PARAM_BOOL(flip_efficiency)               \\\n   OVERLAY_PARAM_BOOL(gpu_power_limit)               \\\n   OVERLAY_PARAM_BOOL(dx_api)                        \\\n   OVERLAY_PARAM_CUSTOM(fps_sampling_period)         \\\n   OVERLAY_PARAM_CUSTOM(output_folder)               \\\n   OVERLAY_PARAM_CUSTOM(output_file)                 \\\n   OVERLAY_PARAM_CUSTOM(font_file)                   \\\n   OVERLAY_PARAM_CUSTOM(font_file_text)              \\\n   OVERLAY_PARAM_CUSTOM(font_glyph_ranges)           \\\n   OVERLAY_PARAM_CUSTOM(no_small_font)               \\\n   OVERLAY_PARAM_CUSTOM(font_size)                   \\\n   OVERLAY_PARAM_CUSTOM(font_size_text)              \\\n   OVERLAY_PARAM_CUSTOM(font_size_secondary)         \\\n   OVERLAY_PARAM_CUSTOM(font_scale)                  \\\n   OVERLAY_PARAM_CUSTOM(font_scale_media_player)     \\\n   OVERLAY_PARAM_CUSTOM(position)                    \\\n   OVERLAY_PARAM_CUSTOM(width)                       \\\n   OVERLAY_PARAM_CUSTOM(height)                      \\\n   OVERLAY_PARAM_CUSTOM(no_display)                  \\\n   OVERLAY_PARAM_CUSTOM(control)                     \\\n   OVERLAY_PARAM_CUSTOM(fps_limit)                   \\\n   OVERLAY_PARAM_CUSTOM(fps_limit_method)            \\\n   OVERLAY_PARAM_CUSTOM(vulkan_present_mode)         \\\n   OVERLAY_PARAM_CUSTOM(vsync)                       \\\n   OVERLAY_PARAM_CUSTOM(gl_vsync)                    \\\n   OVERLAY_PARAM_CUSTOM(gl_size_query)               \\\n   OVERLAY_PARAM_CUSTOM(gl_bind_framebuffer)         \\\n   OVERLAY_PARAM_CUSTOM(gl_dont_flip)                \\\n   OVERLAY_PARAM_CUSTOM(toggle_hud)                  \\\n   OVERLAY_PARAM_CUSTOM(toggle_hud_position)         \\\n   OVERLAY_PARAM_CUSTOM(toggle_preset)               \\\n   OVERLAY_PARAM_CUSTOM(toggle_fps_limit)            \\\n   OVERLAY_PARAM_CUSTOM(toggle_logging)              \\\n   OVERLAY_PARAM_CUSTOM(reset_fps_metrics)           \\\n   OVERLAY_PARAM_CUSTOM(reload_cfg)                  \\\n   OVERLAY_PARAM_CUSTOM(upload_log)                  \\\n   OVERLAY_PARAM_CUSTOM(upload_logs)                 \\\n   OVERLAY_PARAM_CUSTOM(offset_x)                    \\\n   OVERLAY_PARAM_CUSTOM(offset_y)                    \\\n   OVERLAY_PARAM_CUSTOM(background_alpha)            \\\n   OVERLAY_PARAM_CUSTOM(time_format)                 \\\n   OVERLAY_PARAM_CUSTOM(io_read)                     \\\n   OVERLAY_PARAM_CUSTOM(io_write)                    \\\n   OVERLAY_PARAM_CUSTOM(cpu_color)                   \\\n   OVERLAY_PARAM_CUSTOM(gpu_color)                   \\\n   OVERLAY_PARAM_CUSTOM(vram_color)                  \\\n   OVERLAY_PARAM_CUSTOM(ram_color)                   \\\n   OVERLAY_PARAM_CUSTOM(engine_color)                \\\n   OVERLAY_PARAM_CUSTOM(frametime_color)             \\\n   OVERLAY_PARAM_CUSTOM(background_color)            \\\n   OVERLAY_PARAM_CUSTOM(io_color)                    \\\n   OVERLAY_PARAM_CUSTOM(text_color)                  \\\n   OVERLAY_PARAM_CUSTOM(wine_color)                  \\\n   OVERLAY_PARAM_CUSTOM(horizontal_separator_color)  \\\n   OVERLAY_PARAM_CUSTOM(battery_color)               \\\n   OVERLAY_PARAM_CUSTOM(network_color)               \\\n   OVERLAY_PARAM_CUSTOM(alpha)                       \\\n   OVERLAY_PARAM_CUSTOM(log_duration)                \\\n   OVERLAY_PARAM_CUSTOM(pci_dev)                     \\\n   OVERLAY_PARAM_CUSTOM(media_player_name)           \\\n   OVERLAY_PARAM_CUSTOM(media_player_color)          \\\n   OVERLAY_PARAM_CUSTOM(media_player_format)         \\\n   OVERLAY_PARAM_CUSTOM(cpu_text)                    \\\n   OVERLAY_PARAM_CUSTOM(gpu_text)                    \\\n   OVERLAY_PARAM_CUSTOM(log_interval)                \\\n   OVERLAY_PARAM_CUSTOM(permit_upload)               \\\n   OVERLAY_PARAM_CUSTOM(benchmark_percentiles)       \\\n   OVERLAY_PARAM_CUSTOM(help)                        \\\n   OVERLAY_PARAM_CUSTOM(gpu_load_value)              \\\n   OVERLAY_PARAM_CUSTOM(cpu_load_value)              \\\n   OVERLAY_PARAM_CUSTOM(gpu_load_color)              \\\n   OVERLAY_PARAM_CUSTOM(cpu_load_color)              \\\n   OVERLAY_PARAM_CUSTOM(fps_value)                   \\\n   OVERLAY_PARAM_CUSTOM(fps_color)                   \\\n   OVERLAY_PARAM_CUSTOM(cellpadding_y)               \\\n   OVERLAY_PARAM_CUSTOM(table_columns)               \\\n   OVERLAY_PARAM_CUSTOM(blacklist)                   \\\n   OVERLAY_PARAM_CUSTOM(autostart_log)               \\\n   OVERLAY_PARAM_CUSTOM(round_corners)               \\\n   OVERLAY_PARAM_CUSTOM(fsr_steam_sharpness)         \\\n   OVERLAY_PARAM_CUSTOM(fcat_screen_edge)            \\\n   OVERLAY_PARAM_CUSTOM(fcat_overlay_width)          \\\n   OVERLAY_PARAM_CUSTOM(picmip)                      \\\n   OVERLAY_PARAM_CUSTOM(af)                          \\\n   OVERLAY_PARAM_CUSTOM(text_outline_color)          \\\n   OVERLAY_PARAM_CUSTOM(text_outline_thickness)      \\\n   OVERLAY_PARAM_CUSTOM(fps_text)                    \\\n   OVERLAY_PARAM_CUSTOM(device_battery)              \\\n   OVERLAY_PARAM_CUSTOM(fps_metrics)                 \\\n   OVERLAY_PARAM_CUSTOM(network)                     \\\n   OVERLAY_PARAM_CUSTOM(gpu_list)                    \\\n   OVERLAY_PARAM_CUSTOM(fex_stats)                   \\\n   OVERLAY_PARAM_CUSTOM(ftrace)                      \\\n\nenum overlay_param_position {\n   LAYER_POSITION_TOP_LEFT,\n   LAYER_POSITION_TOP_CENTER,\n   LAYER_POSITION_TOP_RIGHT,\n   LAYER_POSITION_MIDDLE_LEFT,\n   LAYER_POSITION_MIDDLE_RIGHT,\n   LAYER_POSITION_BOTTOM_LEFT,\n   LAYER_POSITION_BOTTOM_CENTER,\n   LAYER_POSITION_BOTTOM_RIGHT,\n   // Count must always be the last entry\n   LAYER_POSITION_COUNT,\n};\n\nenum overlay_plots {\n    OVERLAY_PLOTS_frame_timing,\n    OVERLAY_PLOTS_MAX,\n};\n\nenum font_glyph_ranges {\n   FG_KOREAN                  = (1u << 0),\n   FG_CHINESE_FULL            = (1u << 1),\n   FG_CHINESE_SIMPLIFIED      = (1u << 2),\n   FG_JAPANESE                = (1u << 3),\n   FG_CYRILLIC                = (1u << 4),\n   FG_THAI                    = (1u << 5),\n   FG_VIETNAMESE              = (1u << 6),\n   FG_LATIN_EXT_A             = (1u << 7),\n   FG_LATIN_EXT_B             = (1u << 8),\n};\n\nenum gl_size_query {\n   GL_SIZE_DRAWABLE,\n   GL_SIZE_VIEWPORT,\n   GL_SIZE_SCISSORBOX, // needed?\n};\n\nenum fps_limit_method {\n   FPS_LIMIT_METHOD_EARLY,\n   FPS_LIMIT_METHOD_LATE\n};\n\nenum overlay_param_enabled {\n#define OVERLAY_PARAM_BOOL(name) OVERLAY_PARAM_ENABLED_##name,\n#define OVERLAY_PARAM_CUSTOM(name)\n   OVERLAY_PARAMS\n#undef OVERLAY_PARAM_BOOL\n#undef OVERLAY_PARAM_CUSTOM\n   OVERLAY_PARAM_ENABLED_MAX\n};\n\n/* avoid importing vulkan headers\n * also combine colorspaces that use the same transfer function\n */\nenum overlay_transfer_function {\n   NONE = 0,\n   SRGB = (1 << 0),\n   PQ = (1 << 1), /* HDR10 ST2084 */\n   HLG = (1 << 2) /* HDR10 */\n};\n\nstruct overlay_params {\n   bool enabled[OVERLAY_PARAM_ENABLED_MAX];\n   enum overlay_param_position position;\n   int control;\n   uint32_t fps_sampling_period; /* ns */\n   std::vector<float> fps_limit;\n   enum fps_limit_method fps_limit_method;\n   bool help;\n   bool no_display;\n   bool full;\n   bool io_read, io_write, io_stats;\n   unsigned width;\n   unsigned height;\n   int offset_x, offset_y;\n   float round_corners;\n   unsigned vsync;\n   std::string vulkan_present_mode;\n   std::optional<VkPresentModeKHR> m_vulkan_present_mode;\n   int gl_vsync;\n   int gl_bind_framebuffer {0};\n   enum gl_size_query gl_size_query {GL_SIZE_DRAWABLE};\n   bool gl_dont_flip {false};\n   int64_t log_duration, log_interval;\n   unsigned cpu_color, gpu_color, vram_color, ram_color,\n            engine_color, io_color, frametime_color, background_color,\n            text_color, wine_color, battery_color, network_color,\n            horizontal_separator_color;\n   std::vector<unsigned> gpu_load_color;\n   std::vector<unsigned> cpu_load_color;\n   std::vector<unsigned> gpu_load_value;\n   std::vector<unsigned> cpu_load_value;\n   std::vector<unsigned> fps_color;\n   std::vector<unsigned> fps_value;\n   unsigned media_player_color;\n   unsigned table_columns;\n   bool no_small_font;\n   float font_size, font_scale;\n   float font_size_text, font_size_secondary;\n   float font_scale_media_player;\n   float background_alpha, alpha;\n   float cellpadding_y;\n   std::vector<KeySym> toggle_hud;\n   std::vector<KeySym> toggle_preset;\n   std::vector<KeySym> toggle_fps_limit;\n   std::vector<KeySym> toggle_logging;\n   std::vector<KeySym> reload_cfg;\n   std::vector<KeySym> upload_log;\n   std::vector<KeySym> upload_logs;\n   std::vector<KeySym> toggle_hud_position;\n   std::vector<KeySym> reset_fps_metrics;\n   std::string time_format, output_folder, output_file;\n   std::string pci_dev;\n   std::string media_player_name;\n   std::string cpu_text, fps_text;\n   std::map<std::string, std::string> cpu_custom_temp_sensor;\n   std::vector<std::string> blacklist;\n   unsigned autostart_log;\n   std::vector<std::string> media_player_format;\n   std::vector<std::string> benchmark_percentiles;\n   std::vector<std::string> gpu_text;\n   std::string font_file, font_file_text;\n   uint32_t font_glyph_ranges;\n   std::string custom_text_center;\n   std::string custom_text;\n   std::string config_file_path;\n   std::unordered_map<std::string,std::string> options;\n   int permit_upload;\n   int fsr_steam_sharpness;\n   unsigned short fcat_screen_edge;\n   unsigned short fcat_overlay_width;\n   int picmip;\n   int af;\n   std::vector<int> preset;\n   size_t font_params_hash;\n   unsigned text_outline_color;\n   float text_outline_thickness;\n   std::vector<std::string> device_battery;\n   std::vector<std::string> fps_metrics;\n   std::vector<std::string> network;\n   std::vector<unsigned> gpu_list;\n   int transfer_function;\n\n   struct fex_stats_options {\n      bool enabled {false};\n\n      // Enabled Texts\n      bool status {true};\n      bool app_type {true};\n\n      // Graphs\n      bool hot_threads {true};\n      bool jit_load {true};\n\n      // Counts\n      bool sigbus_counts {true};\n      bool smc_counts {true};\n      bool softfloat_counts {true};\n   };\n   fex_stats_options fex_stats{};\n\n   struct ftrace_options {\n      bool enabled {false};\n#ifdef HAVE_FTRACE\n      std::vector<std::shared_ptr<FTrace::Tracepoint>> tracepoints;\n#endif\n   };\n   ftrace_options ftrace {};\n};\n\nconst extern char *overlay_param_names[];\n\nvoid parse_overlay_config(struct overlay_params *params,\n                       const char *env, bool ignore_preset);\nvoid presets(int preset, struct overlay_params *params, bool inherit=false);\nbool parse_preset_config(int preset, struct overlay_params *params);\nvoid add_to_options(struct overlay_params *params, std::string option, std::string value);\n#ifdef __cplusplus\n}\n#endif\nextern std::mutex config_mtx;\nextern std::condition_variable config_cv;\nextern bool config_ready;\nstd::shared_ptr<overlay_params> get_params();\n\n#endif /* MANGOHUD_OVERLAY_PARAMS_H */\n"
  },
  {
    "path": "src/pci_ids.cpp",
    "content": "#include <spdlog/spdlog.h>\n#include <string>\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <iomanip>\n\n#include \"pci_ids.h\"\n\nstd::map<uint32_t /*vendor id*/, std::pair<std::string /*vendor desc*/, std::map<uint32_t /*device id*/, device>>> pci_ids;\n\nstatic std::istream& get_uncommented_line(std::istream& is, std::string &line)\n{\n    while (std::getline(is, line)) {\n        auto c = line.find(\"#\");\n        if (c!=std::string::npos)\n            line.erase(c, std::string::npos);\n        if (line.size())\n            break;\n    }\n    return is;\n}\n\nvoid parse_pciids()\n{\n    std::ifstream file;\n    file.open(\"/usr/share/hwdata/pci.ids\");\n    if (file.fail()){\n        file.open(\"/usr/share/misc/pci.ids\");\n        if (file.fail())\n            SPDLOG_ERROR(\"can't find file pci.ids\");\n    }\n\n    std::string line;\n    size_t tabs = 0;\n\n    uint32_t ven_id = 0, dev_id = 0, subsys_ven_id = 0, subsys_dev_id = 0;\n    std::string desc;\n    std::stringstream ss;\n    while(get_uncommented_line(file, line))\n    {\n        tabs = line.find_first_not_of(\"\\t\");\n\n        ss.str(\"\"); ss.clear();\n        ss << line;\n\n        switch(tabs)\n        {\n            case 0:\n                ss >> std::hex >> ven_id;\n                if (ven_id == 0xFFFF)\n                    return;\n\n                std::getline(ss, desc);\n                pci_ids[ven_id].first = desc;\n            break;\n            case 1:\n            {\n                ss >> std::hex >> dev_id;\n                std::getline(ss, desc); //TODO trim whitespace\n                auto& dev = pci_ids[ven_id].second[dev_id];\n                dev.desc = desc;\n            }\n            break;\n            case 2:\n            {\n                ss >> std::hex >> subsys_ven_id;\n                ss >> subsys_dev_id;\n                std::getline(ss, desc);\n                auto& dev = pci_ids[ven_id].second[dev_id];\n                dev.subsys.push_back({subsys_ven_id, subsys_dev_id, desc});\n            }\n            break;\n            default:\n            break;\n        }\n    }\n}\n"
  },
  {
    "path": "src/pci_ids.h",
    "content": "#pragma once\n#ifndef MANGOHUD_PCI_IDS_H\n#define MANGOHUD_PCI_IDS_H\n\n#include <map>\n#include <vector>\n\nstruct subsys_device\n{\n    uint32_t vendor_id;\n    uint32_t device_id;\n    std::string desc;\n};\n\nstruct device\n{\n    std::string desc;\n    std::vector<subsys_device> subsys;\n};\n\nextern std::map<uint32_t /*vendor id*/, std::pair<std::string /*vendor desc*/, std::map<uint32_t /*device id*/, device>>> pci_ids;\n\nvoid parse_pciids(void);\n\n#endif //MANGOHUD_PCI_IDS_H\n"
  },
  {
    "path": "src/real_dlsym.c",
    "content": "/**\n * \\author Pyry Haulos <pyry.haulos@gmail.com>\n * \\date 2007-2008\n * For conditions of distribution and use, see copyright notice in elfhacks.h\n */\n\n#include <dlfcn.h>\n#include <stdio.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include \"real_dlsym.h\"\n#include \"elfhacks.h\"\n\nvoid *(*__dlopen)(const char *, int) = NULL;\nvoid *(*__dlsym)(void *, const char *) = NULL;\nchar *(*__dlerror)(void) = NULL;\nstatic bool print_dlopen;\nstatic bool print_dlsym;\n\nstatic void get_real_functions()\n{\n    eh_obj_t libdl;\n    int ret;\n\n    const char* libs[] = {\n#if defined(__GLIBC__)\n        \"*libdl.so*\",\n#endif\n        \"*libc.so*\",\n        \"*libc.*.so*\",\n        \"*ld-musl-*.so*\",\n    };\n\n    print_dlopen = getenv(\"MANGOHUD_DEBUG_DLOPEN\") != NULL;\n    print_dlsym = getenv(\"MANGOHUD_DEBUG_DLSYM\") != NULL;\n\n    for (size_t i = 0; i < sizeof(libs) / sizeof(*libs); i++)\n    {\n        ret = eh_find_obj(&libdl, libs[i]);\n        if (ret)\n            continue;\n\n        eh_find_sym(&libdl, \"dlopen\", (void **) &__dlopen);\n        eh_find_sym(&libdl, \"dlsym\", (void **) &__dlsym);\n        eh_find_sym(&libdl, \"dlerror\", (void **) &__dlerror);\n        eh_destroy_obj(&libdl);\n\n        if (__dlopen && __dlsym && __dlerror)\n            break;\n        __dlopen = NULL;\n        __dlsym = NULL;\n        __dlerror = NULL;\n    }\n\n    if (!__dlopen && !__dlsym && !__dlerror)\n    {\n        fprintf(stderr, \"MANGOHUD: Can't get dlopen(), dlsym() and dlerror()\\n\");\n        exit(ret ? ret : 1);\n    }\n}\n\n/**\n * \\brief dlopen() wrapper, just passes calls to real dlopen()\n *        and writes information to standard output\n */\nvoid *real_dlopen(const char *filename, int flag)\n{\n    if (__dlopen == NULL)\n        get_real_functions();\n\n    void *result = __dlopen(filename, flag);\n\n    if (print_dlopen) {\n        printf(\"dlopen(%s, \", filename);\n        const char *fmt = \"%s\";\n        #define FLAG(test) if (flag & test) { printf(fmt, #test); fmt = \"|%s\"; }\n        FLAG(RTLD_LAZY)\n        FLAG(RTLD_NOW)\n        FLAG(RTLD_GLOBAL)\n        FLAG(RTLD_LOCAL)\n        FLAG(RTLD_NODELETE)\n        FLAG(RTLD_NOLOAD)\n#ifdef RTLD_DEEPBIND\n        FLAG(RTLD_DEEPBIND)\n#endif\n        #undef FLAG\n        printf(\") = %p\\n\", result);\n    }\n\n    return result;\n}\n\n/**\n * \\brief dlsym() wrapper, passes calls to real dlsym() and\n *        writes information to standard output\n */\nvoid *real_dlsym(void *handle, const char *symbol)\n{\n    if (__dlsym == NULL)\n        get_real_functions();\n\n    void *result = __dlsym(handle, symbol);\n\n    if (print_dlsym)\n        printf(\"dlsym(%p, %s) = %p\\n\", handle, symbol, result);\n\n    return result;\n}\n\nchar* real_dlerror(void)\n{\n    if (__dlerror == NULL)\n        get_real_functions();\n    return __dlerror();\n}\n\nvoid* get_proc_address(const char* name) {\n    return real_dlsym(RTLD_NEXT, name);\n}\n"
  },
  {
    "path": "src/real_dlsym.h",
    "content": "#pragma once\n#ifndef MANGOHUD_REAL_DLSYM_H\n#define MANGOHUD_REAL_DLSYM_H\n\n#define EXPORT_C_(type) extern \"C\" __attribute__((__visibility__(\"default\"))) type\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\nvoid *real_dlopen(const char *filename, int flag);\nvoid* real_dlsym( void*, const char* );\nvoid* get_proc_address(const char* name);\nchar* real_dlerror(void);\n#ifdef __cplusplus\n}\n#endif\n\n#endif //MANGOHUD_REAL_DLSYM_H\n"
  },
  {
    "path": "src/shared_x11.cpp",
    "content": "#include <cstdlib>\n#include <iostream>\n#include <memory>\n#include <functional>\n#include <spdlog/spdlog.h>\n#include \"shared_x11.h\"\n#include \"loaders/loader_x11.h\"\n#include \"hud_elements.h\"\n\nstatic std::unique_ptr<Display, std::function<void(Display*)>> display;\n\nbool init_x11() {\n    static bool failed = false;\n    if (failed)\n        return false;\n\n    if (display)\n        return true;\n\n    auto libx11 = get_libx11();\n\n    if (!libx11->IsLoaded()) {\n        SPDLOG_ERROR(\"X11 loader failed to load\");\n        failed = true;\n        return false;\n    }\n\n    const char *displayid = getenv(\"DISPLAY\");\n\n    if (!displayid || !*displayid) {\n        SPDLOG_DEBUG(\"DISPLAY env is not set or empty\");\n        failed = true;\n        return false;\n    }\n\n    display = { libx11->XOpenDisplay(displayid),\n        [libx11](Display* dpy) {\n            if (dpy)\n                libx11->XCloseDisplay(dpy);\n        }\n    };\n\n    failed = !display;\n    if (failed) {\n        SPDLOG_ERROR(\"XOpenDisplay failed to open display '{}'\", displayid);\n        return false;\n    }\n\n    if (HUDElements.display_server == HUDElements.display_servers::UNKNOWN) {\n        int opcode, event, error;\n        if (libx11->XQueryExtension(display.get(), \"XWAYLAND\", &opcode, &event, &error))\n\t\t    HUDElements.display_server = HUDElements.display_servers::XWAYLAND;\n        else\n            HUDElements.display_server = HUDElements.display_servers::XORG;\n\n\t}\n\n    return !!display;\n}\n\nDisplay* get_xdisplay()\n{\n    return display.get();\n}\n"
  },
  {
    "path": "src/shared_x11.h",
    "content": "#pragma once\n#ifndef MANGOHUD_SHARED_X11_H\n#define MANGOHUD_SHARED_X11_H\n\n#include <X11/Xlib.h>\n\nDisplay* get_xdisplay();\nbool init_x11();\n\n#endif //MANGOHUD_SHARED_X11_H\n"
  },
  {
    "path": "src/shell.cpp",
    "content": "#include \"shell.h\"\n#include <thread>\n#include <iostream>\n#include <sys/wait.h>\n#include <spdlog/spdlog.h>\n#include \"string_utils.h\"\n#include <array>\n\nstd::string Shell::readOutput() {\n    std::this_thread::sleep_for(std::chrono::milliseconds(50));\n\n    std::array<char, 128> buffer;\n    std::string result;\n    ssize_t count;\n    while ((count = ::read(from_shell[0], buffer.data(), buffer.size())) > 0) {\n        result.append(buffer.data(), count);\n    }\n\n    // Split the result into lines and return the last line\n    std::istringstream stream(result);\n    std::string line;\n    std::string last_line;\n    while (std::getline(stream, line)) {\n        last_line = line;\n    }\n\n    SPDLOG_DEBUG(\"Shell: recieved output: {}\", last_line);\n    return last_line;\n}\n\nShell::Shell() {\n    if (stat(\"/run/pressure-vessel\", &stat_buffer) == 0)\n        runtime = true;\n\n    static bool failed;\n    if (pipe(to_shell) == -1) {\n        SPDLOG_ERROR(\"Failed to create to_shell pipe: {}\", strerror(errno));\n        failed = true;\n    }\n\n    if (pipe(from_shell) == -1) {\n        SPDLOG_ERROR(\"Failed to create from_shell pipe: {}\", strerror(errno));\n        failed = true;\n    }\n\n    // if either pipe fails, there's no point in continuing.\n    if (failed){\n        SPDLOG_ERROR(\"Shell has failed, will not be able to use exec\");\n        return;\n    }\n\n    shell_pid = fork();\n\n    if (shell_pid == 0) { // Child process\n        close(to_shell[1]);\n        close(from_shell[0]);\n\n        dup2(to_shell[0], STDIN_FILENO);\n        dup2(from_shell[1], STDOUT_FILENO);\n        dup2(from_shell[1], STDERR_FILENO);\n        execl(\"/bin/sh\", \"sh\", \"-c\", \"unset LD_PRELOAD; exec /bin/sh\", nullptr);\n        exit(1); // Exit if execl fails\n    } else {\n        close(to_shell[0]);\n        close(from_shell[1]);\n\n        // Set the read end of the from_shell pipe to non-blocking\n        setNonBlocking(from_shell[0]);\n    }\n    success = true;\n}\n\nstd::string Shell::exec(std::string cmd) {\n    if (!success)\n        return \"\";\n\n    writeCommand(cmd);\n    return readOutput();\n}\n\nvoid Shell::writeCommand(std::string command) {\n    if (write(to_shell[1], command.c_str(), command.length()) == -1)\n        SPDLOG_ERROR(\"Failed to write to shell\");\n    \n    if (runtime)\n        command = \"steam-runtime-launch-client --alongside-steam --host -- \" + command;\n    \n    trim(command);\n    SPDLOG_DEBUG(\"Shell: wrote command: {}\", command);\n}\n\nShell::~Shell() {\n    close(to_shell[1]);\n    close(from_shell[0]);\n    waitpid(shell_pid, nullptr, 0);\n}\n"
  },
  {
    "path": "src/shell.h",
    "content": "#pragma once\n#include <fcntl.h>\n#include <unistd.h>\n#include <cstring>\n#ifdef __linux__\n#include <sys/wait.h>\n#endif\n#include <string>\n#include <memory>\n#include <sys/stat.h>\n\nclass Shell {\nprivate:\n    int to_shell[2];\n    int from_shell[2];\n    pid_t shell_pid;\n    bool success;\n    struct stat stat_buffer;\n    bool runtime = false;\n\n#ifdef __linux__\n    void setNonBlocking(int fd) {\n        int flags = fcntl(fd, F_GETFL, 0);\n        fcntl(fd, F_SETFL, flags | O_NONBLOCK);\n    }\n#endif\n\n    void writeCommand(std::string command);\n    std::string readOutput();\n\npublic:\n    Shell();\n    ~Shell();\n    std::string exec(std::string cmd);\n\n};\n\nextern std::unique_ptr<Shell> shell;\n"
  },
  {
    "path": "src/string_utils.h",
    "content": "#pragma once\n#ifndef MANGOHUD_STRING_UTILS_H\n#define MANGOHUD_STRING_UTILS_H\n\n#include <string>\n#include <vector>\n#include <iomanip>\n#include <iostream>\n#include <sstream>\n#include <algorithm>\n#include <cctype>\n#include <locale>\n#include <cstring>\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wunused-function\"\n#ifdef __LCC__\n    #pragma diag_suppress 3313  // Suppress unused function warnings\n#endif\n\n// https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring#217605\n// trim from start (in place)\nstatic inline void ltrim(std::string &s) {\n    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {\n        return !std::isspace(ch);\n    }));\n}\n\n// trim from end (in place)\nstatic inline void rtrim(std::string &s) {\n    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {\n        return !std::isspace(ch);\n    }).base(), s.end());\n}\n\n// trim from both ends (in place)\nstatic inline void trim(std::string &s) {\n    ltrim(s);\n    rtrim(s);\n}\n\n// trim from start (copying)\nstatic inline std::string ltrim_copy(std::string s) {\n    ltrim(s);\n    return s;\n}\n\n// trim from end (copying)\nstatic inline std::string rtrim_copy(std::string s) {\n    rtrim(s);\n    return s;\n}\n\n// trim from both ends (copying)\nstatic inline std::string trim_copy(std::string s) {\n    trim(s);\n    return s;\n}\n\nstatic bool starts_with(const std::string& s,  const char *t) {\n    return s.rfind(t, 0) == 0;\n}\n\nstatic bool ends_with(const std::string& s,  const char *t, bool icase = false) {\n    std::string s0(s);\n    std::string s1(t);\n\n    if (s0.size() < s1.size())\n        return false;\n\n    if (icase) {\n        std::transform(s0.begin(), s0.end(), s0.begin(), ::tolower);\n        std::transform(s1.begin(), s1.end(), s1.begin(), ::tolower);\n    }\n\n    size_t pos = s0.size() - s1.size();\n    return (s0.rfind(s1, pos) == pos);\n}\n\nstatic bool iequal(std::string_view lhs, std::string_view rhs) {\n    return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), [](unsigned char x, unsigned char y) {\n        return std::toupper(x) == std::toupper(y);\n    });\n};\n\nstatic std::string_view strip_prefix(const std::string_view input, const std::string_view prefix) {\n    if (input.size() >= prefix.size() && iequal(input.substr(0, prefix.size()), prefix))\n        return input.substr(prefix.size());\n    return input;\n};\n\nstatic std::string_view strip_suffix(const std::string_view input, const std::string_view suffix) {\n    if (input.size() >= suffix.size() && iequal(input.substr(input.size() - suffix.size()), suffix))\n        return input.substr(0, input.size() - suffix.size());\n    return input;\n};\n\ntemplate<typename T>\nstatic std::string itox(T i) {\n    std::stringstream ss;\n    ss << \"0x\"\n        << std::setfill ('0') << std::setw(sizeof(T) * 2)\n        << std::hex << i;\n    return ss.str();\n}\n\nstatic bool try_stoi(int& val, const std::string& str)\n{\n    if (sscanf(str.c_str(), \"%d\", &val) == 1)\n        return true;\n    return false;\n}\n\nstatic bool try_stoull(unsigned long long& val, const std::string& str)\n{\n    if (sscanf(str.c_str(), \"%llu\", &val) == 1)\n        return true;\n    return false;\n}\n\nstatic float parse_float(const std::string& s, std::size_t* float_len = nullptr){\n    std::stringstream ss(s);\n    ss.imbue(std::locale::classic());\n    float ret;\n    ss >> ret;\n    if(ss.fail()) throw std::invalid_argument(\"parse_float: Not a float\");\n    if(float_len != nullptr){\n        auto pos = ss.tellg();\n        if(ss.fail()) *float_len = s.size();\n        else *float_len = pos;\n    }\n    return ret;\n}\n\nstatic std::vector<std::string> str_tokenize(const std::string& s, const std::string& delims = \",:+\")\n{\n   std::vector<std::string> v;\n   size_t old_n = 0, new_n = 0;\n\n   while (old_n < s.size()){\n      new_n = s.find_first_of(delims, old_n);\n      auto c = s.substr(old_n, new_n - old_n);\n      if (old_n != new_n)\n         v.push_back(c);\n      if (new_n == std::string::npos)\n          break;\n      old_n = new_n + 1;\n   }\n   return v;\n}\n\nstatic void trim_char(char* str) {\n    if(!str)\n        return;\n\n    char* ptr = str;\n    int len = strlen(ptr);\n\n    while(len-1 > 0 && isspace(ptr[len-1]))\n        ptr[--len] = 0;\n\n    while(*ptr && isspace(*ptr))\n        ++ptr, --len;\n\n    memmove(str, ptr, len + 1);\n}\n\n#pragma GCC diagnostic pop\n\n#endif //MANGOHUD_STRING_UTILS_H\n"
  },
  {
    "path": "src/timing.hpp",
    "content": "#pragma once\n#ifndef MANGOHUD_TIMING_HPP\n#define MANGOHUD_TIMING_HPP\n\n#include <chrono>\n\n#include \"mesa/util/os_time.h\"\n\nclass MesaClock {\npublic:\n    using rep = int64_t;\n    using period = std::nano;\n    using duration = std::chrono::duration<rep, period>;\n    using time_point = std::chrono::time_point<MesaClock>;\n    const static bool is_steady = true;\n    static time_point now() noexcept {\n        return time_point(duration(os_time_get_nano()));\n    }\n};\n\nusing Clock = MesaClock;\n\n#endif //MANGOHUD_TIMING_HPP\n"
  },
  {
    "path": "src/vulkan.cpp",
    "content": "/*\n * Copyright © 2019 Intel Corporation\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice (including the next\n * paragraph) shall be included in all copies or substantial portions of the\n * 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,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n#ifdef _WIN32\n#include <windows.h>\n#endif\n#include <algorithm>\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <thread>\n#include <chrono>\n#include <unordered_map>\n#include <mutex>\n#include <vector>\n#include <list>\n#include <array>\n#include <iomanip>\n#include <sstream>\n#include <inttypes.h>\n#include <spdlog/spdlog.h>\n#include <imgui.h>\n\n#include \"mesa/util/macros.h\" // defines \"restrict\" for vk_util.h\n#include \"mesa/util/os_socket.h\"\n#include <vulkan/vulkan.h>\n#include <vulkan/vk_enum_string_helper.h>\n#include <vulkan/vk_layer.h>\n#include <vulkan/vk_util.h>\n#include \"vk_enum_to_str.h\"\n#include \"vk_dispatch_table.h\"\n\n#include \"overlay.h\"\n#include \"notify.h\"\n#include \"blacklist.h\"\n#include \"pci_ids.h\"\n#if defined(HAVE_WAYLAND)\n#include \"wayland_hook.h\"\n#endif\n#include \"real_dlsym.h\"\n#include \"file_utils.h\"\n#ifdef __linux__\n#include <dlfcn.h>\n#include \"implot.h\"\n#endif\n#include \"imgui_utils.h\"\n#include \"fps_limiter.h\"\n\nusing namespace std;\n\nfloat offset_x, offset_y, hudSpacing;\nint hudFirstRow, hudSecondRow;\nVkPhysicalDeviceDriverProperties driverProps = {};\n\n#if !defined(_WIN32)\nnamespace MangoHud { namespace GL {\n   extern swapchain_stats sw_stats;\n}}\n#endif\n\n/* Mapped from VkInstace/VkPhysicalDevice */\nstruct instance_data {\n   struct vk_instance_dispatch_table vtable;\n   struct vk_physical_device_dispatch_table pd_vtable;\n   VkInstance instance;\n   struct overlay_params params;\n   uint32_t api_version;\n   string engineName, engineVersion;\n   enum EngineTypes engine;\n   notify_thread notifier;\n   int control_client;\n   uint32_t applicationVersion;\n};\n\n/* Mapped from VkDevice */\nstruct queue_data;\nstruct device_data {\n   struct instance_data *instance;\n\n   PFN_vkSetDeviceLoaderData set_device_loader_data;\n\n   struct vk_device_dispatch_table vtable;\n   VkPhysicalDevice physical_device;\n   VkDevice device;\n\n   VkPhysicalDeviceProperties properties;\n\n   struct queue_data *graphic_queue;\n\n   std::vector<struct queue_data *> queues;\n};\n\n/* Mapped from VkCommandBuffer */\nstruct command_buffer_data {\n   struct device_data *device;\n\n   VkCommandBufferLevel level;\n\n   VkCommandBuffer cmd_buffer;\n\n   struct queue_data *queue_data;\n};\n\n/* Mapped from VkQueue */\nstruct queue_data {\n   struct device_data *device;\n\n   VkQueue queue;\n   VkQueueFlags flags;\n   uint32_t family_index;\n};\n\nstruct overlay_draw {\n   VkCommandBuffer command_buffer;\n\n   VkSemaphore cross_engine_semaphore;\n\n   VkSemaphore semaphore;\n   VkFence fence;\n\n   VkBuffer vertex_buffer;\n   VkDeviceMemory vertex_buffer_mem;\n   VkDeviceSize vertex_buffer_size;\n\n   VkBuffer index_buffer;\n   VkDeviceMemory index_buffer_mem;\n   VkDeviceSize index_buffer_size;\n};\n\n/* Mapped from VkSwapchainKHR */\nstruct swapchain_data {\n   struct device_data *device;\n\n   VkSwapchainKHR swapchain;\n   unsigned width, height;\n   VkFormat format;\n\n   std::vector<VkImage> images;\n   std::vector<VkImageView> image_views;\n   std::vector<VkFramebuffer> framebuffers;\n\n   VkRenderPass render_pass;\n\n   VkDescriptorPool descriptor_pool;\n   VkDescriptorSetLayout descriptor_layout;\n   VkDescriptorSet descriptor_set;\n\n   VkSampler font_sampler;\n\n   VkPipelineLayout pipeline_layout;\n   VkPipeline pipeline;\n\n   VkCommandPool command_pool;\n\n   std::vector<overlay_draw *> draws; /* vector of struct overlay_draw */\n\n   bool font_uploaded;\n   VkImage font_image;\n   VkImageView font_image_view;\n   VkDeviceMemory font_mem;\n   VkBuffer upload_font_buffer;\n   VkDeviceMemory upload_font_buffer_mem;\n\n   struct imgui_contexts imgui_contexts;\n\n   ImFontAtlas* font_atlas;\n   ImVec2 window_size;\n\n   struct swapchain_stats sw_stats;\n};\n\n// single global lock, for simplicity\nstd::mutex global_lock;\ntypedef std::lock_guard<std::mutex> scoped_lock;\nstd::unordered_map<uint64_t, void *> vk_object_to_data;\n\nthread_local ImGuiContext* __MesaImGui;\n\n#define HKEY(obj) ((uint64_t)(obj))\n#define FIND(type, obj) (reinterpret_cast<type *>(find_object_data(HKEY(obj))))\n\nstatic void *find_object_data(uint64_t obj)\n{\n   ::scoped_lock lk(global_lock);\n   return vk_object_to_data[obj];\n}\n\nstatic void map_object(uint64_t obj, void *data)\n{\n   ::scoped_lock lk(global_lock);\n   vk_object_to_data[obj] = data;\n}\n\nstatic void unmap_object(uint64_t obj)\n{\n   ::scoped_lock lk(global_lock);\n   vk_object_to_data.erase(obj);\n}\n\n/**/\n\n#define VK_CHECK(expr) \\\n   do { \\\n      VkResult __result = (expr); \\\n      if (__result != VK_SUCCESS) { \\\n         SPDLOG_ERROR(\"'{}' line {} failed with {}\", \\\n                 #expr, __LINE__, vk_Result_to_str(__result)); \\\n      } \\\n   } while (0)\n\nnamespace {\n// Walks a chain and returns a pointer-to-pointer handle to the given type or `nullptr` if not found.\n// The handle allows the caller to modify and relink the chain.\nVkBaseInStructure **\nvk_find_next_struct(void **chain, VkStructureType type) {\n  VkBaseInStructure **pPrev = (VkBaseInStructure **)chain;\n  while (*pPrev) {\n    if ((*pPrev)->sType == type)\n      return pPrev;\n    pPrev = (VkBaseInStructure **)&(*pPrev)->pNext;\n  }\n  return nullptr;\n}\n}\n\n/**/\n\nstatic void shutdown_swapchain_font(struct swapchain_data*);\n\nstatic VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,\n                                                          VkLayerFunction func)\n{\n   vk_foreach_struct(item, pCreateInfo->pNext) {\n      if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO &&\n          ((VkLayerInstanceCreateInfo *) item)->function == func)\n         return (VkLayerInstanceCreateInfo *) item;\n   }\n   UNREACHABLE(\"instance chain info not found\");\n   return NULL;\n}\n\nstatic VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo,\n                                                      VkLayerFunction func)\n{\n   vk_foreach_struct(item, pCreateInfo->pNext) {\n      if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO &&\n          ((VkLayerDeviceCreateInfo *) item)->function == func)\n         return (VkLayerDeviceCreateInfo *)item;\n   }\n   UNREACHABLE(\"device chain info not found\");\n   return NULL;\n}\n\n/**/\n\nstatic struct instance_data *new_instance_data(VkInstance instance)\n{\n   struct instance_data *data = new instance_data();\n   data->instance = instance;\n   data->params = {};\n   data->params.control = -1;\n   data->control_client = -1;\n   map_object(HKEY(data->instance), data);\n   return data;\n}\n\nstatic void destroy_instance_data(struct instance_data *data)\n{\n   if (data->params.control >= 0)\n      os_socket_close(data->params.control);\n   unmap_object(HKEY(data->instance));\n   delete data;\n}\n\nstatic void instance_data_map_physical_devices(struct instance_data *instance_data,\n                                               bool map)\n{\n   uint32_t physicalDeviceCount = 0;\n   instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,\n                                                  &physicalDeviceCount,\n                                                  NULL);\n\n   std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);\n   instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance,\n                                                  &physicalDeviceCount,\n                                                  physicalDevices.data());\n\n   for (uint32_t i = 0; i < physicalDeviceCount; i++) {\n      if (map)\n         map_object(HKEY(physicalDevices[i]), instance_data);\n      else\n         unmap_object(HKEY(physicalDevices[i]));\n   }\n}\n\n/**/\nstatic struct device_data *new_device_data(VkDevice device, struct instance_data *instance)\n{\n   struct device_data *data = new device_data();\n   data->instance = instance;\n   data->device = device;\n   map_object(HKEY(data->device), data);\n   return data;\n}\n\nstatic struct queue_data *new_queue_data(VkQueue queue,\n                                         const VkQueueFamilyProperties *family_props,\n                                         uint32_t family_index,\n                                         struct device_data *device_data)\n{\n   struct queue_data *data = new queue_data();\n   data->device = device_data;\n   data->queue = queue;\n   data->flags = family_props->queueFlags;\n   data->family_index = family_index;\n   map_object(HKEY(data->queue), data);\n\n   if (data->flags & VK_QUEUE_GRAPHICS_BIT)\n      device_data->graphic_queue = data;\n\n   return data;\n}\n\nstatic void destroy_queue(struct queue_data *data)\n{\n   unmap_object(HKEY(data->queue));\n   delete data;\n}\n\nstatic void device_map_queues(struct device_data *data,\n                              const VkDeviceCreateInfo *pCreateInfo)\n{\n   uint32_t n_queues = 0;\n   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++)\n      n_queues += pCreateInfo->pQueueCreateInfos[i].queueCount;\n   data->queues.resize(n_queues);\n\n   struct instance_data *instance_data = data->instance;\n   uint32_t n_family_props;\n   instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,\n                                                                &n_family_props,\n                                                                NULL);\n   std::vector<VkQueueFamilyProperties> family_props(n_family_props);\n   instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device,\n                                                                &n_family_props,\n                                                                family_props.data());\n\n   uint32_t queue_index = 0;\n   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {\n      for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) {\n         VkQueue queue;\n         data->vtable.GetDeviceQueue(data->device,\n                                     pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex,\n                                     j, &queue);\n\n         VK_CHECK(data->set_device_loader_data(data->device, queue));\n\n         data->queues[queue_index++] =\n            new_queue_data(queue, &family_props[pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex],\n                           pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, data);\n      }\n   }\n}\n\nstatic void device_unmap_queues(struct device_data *data)\n{\n   for (auto q : data->queues)\n      destroy_queue(q);\n}\n\nstatic void destroy_device_data(struct device_data *data)\n{\n   unmap_object(HKEY(data->device));\n   delete data;\n}\n\n/**/\nstatic struct command_buffer_data *new_command_buffer_data(VkCommandBuffer cmd_buffer,\n                                                           VkCommandBufferLevel level,\n                                                           struct device_data *device_data)\n{\n   struct command_buffer_data *data = new command_buffer_data();\n   data->device = device_data;\n   data->cmd_buffer = cmd_buffer;\n   data->level = level;\n   map_object(HKEY(data->cmd_buffer), data);\n   return data;\n}\n\nstatic void destroy_command_buffer_data(struct command_buffer_data *data)\n{\n   unmap_object(HKEY(data->cmd_buffer));\n   delete data;\n}\n\n/**/\nstatic struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain,\n                                                 struct device_data *device_data)\n{\n   struct instance_data *instance_data = device_data->instance;\n   struct swapchain_data *data = new swapchain_data();\n   data->device = device_data;\n   data->swapchain = swapchain;\n   data->window_size = ImVec2(instance_data->params.width, instance_data->params.height);\n   data->font_atlas = IM_NEW(ImFontAtlas);\n   map_object(HKEY(data->swapchain), data);\n   return data;\n}\n\nstatic void destroy_swapchain_data(struct swapchain_data *data)\n{\n   unmap_object(HKEY(data->swapchain));\n   delete data;\n}\n\nstatic struct overlay_draw *get_overlay_draw(struct swapchain_data *data, unsigned image_idx)\n{\n   struct device_data *device_data = data->device;\n   const size_t images_count = data->images.size();\n   if (data->draws.size() < images_count) {\n      data->draws.resize(images_count, nullptr);\n   }\n   struct overlay_draw *draw = data->draws[image_idx];\n\n   VkSemaphoreCreateInfo sem_info = {};\n   sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n\n   if (draw) {\n      VK_CHECK(device_data->vtable.WaitForFences(device_data->device, 1,\n                                                 &draw->fence, VK_TRUE, ~0ull));\n      VK_CHECK(device_data->vtable.ResetFences(device_data->device,\n                                               1, &draw->fence));\n      return draw;\n   }\n\n   draw = new overlay_draw();\n\n   VkCommandBufferAllocateInfo cmd_buffer_info = {};\n   cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n   cmd_buffer_info.commandPool = data->command_pool;\n   cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n   cmd_buffer_info.commandBufferCount = 1;\n   VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device,\n                                                       &cmd_buffer_info,\n                                                       &draw->command_buffer));\n   VK_CHECK(device_data->set_device_loader_data(device_data->device,\n                                                draw->command_buffer));\n\n\n   VkFenceCreateInfo fence_info = {};\n   fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n   VK_CHECK(device_data->vtable.CreateFence(device_data->device,\n                                            &fence_info,\n                                            NULL,\n                                            &draw->fence));\n\n   VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,\n                                                NULL, &draw->semaphore));\n   VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info,\n                                                NULL, &draw->cross_engine_semaphore));\n\n   data->draws[image_idx] = draw;\n\n   return draw;\n}\n\nstatic void snapshot_swapchain_frame(struct swapchain_data *data)\n{\n   struct device_data *device_data = data->device;\n   struct instance_data *instance_data = device_data->instance;\n   update_hud_info(data->sw_stats, instance_data->params, device_data->properties.vendorID);\n   check_keybinds(instance_data->params);\n#ifdef __linux__\n   if (instance_data->params.control >= 0) {\n      control_client_check(instance_data->params.control, instance_data->control_client, gpu.c_str());\n      process_control_socket(instance_data->control_client, instance_data->params);\n   }\n#endif\n}\n\nstatic void compute_swapchain_display(struct swapchain_data *data)\n{\n   struct device_data *device_data = data->device;\n   struct instance_data *instance_data = device_data->instance;\n\n   if (get_params()->no_display)\n      return;\n\n   auto saved_imgui_context = get_current_imgui_contexts();\n   make_imgui_contexts_current(data->imgui_contexts);\n\n   if (HUDElements.colors.update)\n      HUDElements.convert_colors(instance_data->params);\n\n   ImGui::NewFrame();\n   {\n      ::scoped_lock lk(instance_data->notifier.mutex);\n      overlay_new_frame(instance_data->params);\n      position_layer(data->sw_stats, instance_data->params, data->window_size);\n      render_imgui(data->sw_stats, instance_data->params, data->window_size, true);\n      overlay_end_frame();\n   }\n   ImGui::EndFrame();\n   ImGui::Render();\n\n   make_imgui_contexts_current(saved_imgui_context);\n}\n\nstatic uint32_t vk_memory_type(struct device_data *data,\n                               VkMemoryPropertyFlags properties,\n                               uint32_t type_bits)\n{\n    VkPhysicalDeviceMemoryProperties prop;\n    data->instance->pd_vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop);\n    for (uint32_t i = 0; i < prop.memoryTypeCount; i++)\n        if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<<i))\n            return i;\n    return 0xFFFFFFFF; // Unable to find memoryType\n}\n\nstatic void update_image_descriptor(struct swapchain_data *data, VkImageView image_view, VkDescriptorSet set)\n{\n   struct device_data *device_data = data->device;\n   /* Descriptor set */\n   VkDescriptorImageInfo desc_image[1] = {};\n   desc_image[0].sampler = data->font_sampler;\n   desc_image[0].imageView = image_view;\n   desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n   VkWriteDescriptorSet write_desc[1] = {};\n   write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n   write_desc[0].dstSet = set;\n   write_desc[0].descriptorCount = 1;\n   write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n   write_desc[0].pImageInfo = desc_image;\n   device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL);\n}\n\nstatic void upload_image_data(struct device_data *device_data,\n                              VkCommandBuffer command_buffer,\n                              void *pixels,\n                              VkDeviceSize upload_size,\n                              uint32_t width,\n                              uint32_t height,\n                              VkBuffer& upload_buffer,\n                              VkDeviceMemory& upload_buffer_mem,\n                              VkImage image)\n{\n   /* Upload buffer */\n   VkBufferCreateInfo buffer_info = {};\n   buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n   buffer_info.size = upload_size;\n   buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n   buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n   VK_CHECK(device_data->vtable.CreateBuffer(device_data->device, &buffer_info,\n                                             NULL, &upload_buffer));\n   VkMemoryRequirements upload_buffer_req;\n   device_data->vtable.GetBufferMemoryRequirements(device_data->device,\n                                                   upload_buffer,\n                                                   &upload_buffer_req);\n   VkMemoryAllocateInfo upload_alloc_info = {};\n   upload_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n   upload_alloc_info.allocationSize = upload_buffer_req.size;\n   upload_alloc_info.memoryTypeIndex = vk_memory_type(device_data,\n                                                      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,\n                                                      upload_buffer_req.memoryTypeBits);\n   VK_CHECK(device_data->vtable.AllocateMemory(device_data->device,\n                                               &upload_alloc_info,\n                                               NULL,\n                                               &upload_buffer_mem));\n   VK_CHECK(device_data->vtable.BindBufferMemory(device_data->device,\n                                                 upload_buffer,\n                                                 upload_buffer_mem, 0));\n\n   /* Upload to Buffer */\n   char* map = NULL;\n   VK_CHECK(device_data->vtable.MapMemory(device_data->device,\n                                          upload_buffer_mem,\n                                          0, upload_size, 0, (void**)(&map)));\n   memcpy(map, pixels, upload_size);\n   VkMappedMemoryRange range[1] = {};\n   range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n   range[0].memory = upload_buffer_mem;\n   range[0].size = upload_size;\n   VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 1, range));\n   device_data->vtable.UnmapMemory(device_data->device,\n                                   upload_buffer_mem);\n\n   /* Copy buffer to image */\n   VkImageMemoryBarrier copy_barrier[1] = {};\n   copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n   copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n   copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n   copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n   copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n   copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n   copy_barrier[0].image = image;\n   copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n   copy_barrier[0].subresourceRange.levelCount = 1;\n   copy_barrier[0].subresourceRange.layerCount = 1;\n   device_data->vtable.CmdPipelineBarrier(command_buffer,\n                                          VK_PIPELINE_STAGE_HOST_BIT,\n                                          VK_PIPELINE_STAGE_TRANSFER_BIT,\n                                          0, 0, NULL, 0, NULL,\n                                          1, copy_barrier);\n\n   VkBufferImageCopy region = {};\n   region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n   region.imageSubresource.layerCount = 1;\n   region.imageExtent.width = width;\n   region.imageExtent.height = height;\n   region.imageExtent.depth = 1;\n   device_data->vtable.CmdCopyBufferToImage(command_buffer,\n                                            upload_buffer,\n                                            image,\n                                            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,\n                                            1, &region);\n\n   VkImageMemoryBarrier use_barrier[1] = {};\n   use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n   use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n   use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;\n   use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n   use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n   use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n   use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n   use_barrier[0].image = image;\n   use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n   use_barrier[0].subresourceRange.levelCount = 1;\n   use_barrier[0].subresourceRange.layerCount = 1;\n   device_data->vtable.CmdPipelineBarrier(command_buffer,\n                                          VK_PIPELINE_STAGE_TRANSFER_BIT,\n                                          VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,\n                                          0,\n                                          0, NULL,\n                                          0, NULL,\n                                          1, use_barrier);\n}\n\nstatic void create_image(struct swapchain_data *data,\n                        VkDescriptorSet descriptor_set,\n                        uint32_t width,\n                        uint32_t height,\n                        VkFormat format,\n                        VkImage& image,\n                        VkDeviceMemory& image_mem,\n                        VkImageView& image_view)\n{\n   struct device_data *device_data = data->device;\n\n   VkImageCreateInfo image_info = {};\n   image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n   image_info.imageType = VK_IMAGE_TYPE_2D;\n   image_info.format = format;\n   image_info.extent.width = width;\n   image_info.extent.height = height;\n   image_info.extent.depth = 1;\n   image_info.mipLevels = 1;\n   image_info.arrayLayers = 1;\n   image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n   image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n   image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;\n   image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n   image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n   VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,\n                                            NULL, &image));\n   VkMemoryRequirements font_image_req;\n   device_data->vtable.GetImageMemoryRequirements(device_data->device,\n                                                  image, &font_image_req);\n   VkMemoryAllocateInfo image_alloc_info = {};\n   image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n   image_alloc_info.allocationSize = font_image_req.size;\n   image_alloc_info.memoryTypeIndex = vk_memory_type(device_data,\n                                                     VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,\n                                                     font_image_req.memoryTypeBits);\n   VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,\n                                               NULL, &image_mem));\n   VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,\n                                                image,\n                                                image_mem, 0));\n\n   /* Font image view */\n   VkImageViewCreateInfo view_info = {};\n   view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n   view_info.image = image;\n   view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n   view_info.format = format;\n   view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n   view_info.subresourceRange.levelCount = 1;\n   view_info.subresourceRange.layerCount = 1;\n   VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,\n                                                NULL, &image_view));\n\n   update_image_descriptor(data, image_view, descriptor_set);\n}\n\nstatic VkDescriptorSet create_image_with_desc(struct swapchain_data *data,\n                                          uint32_t width,\n                                          uint32_t height,\n                                          VkFormat format,\n                                          VkImage& image,\n                                          VkDeviceMemory& image_mem,\n                                          VkImageView& image_view)\n{\n   struct device_data *device_data = data->device;\n\n   VkDescriptorSet descriptor_set {};\n\n   VkDescriptorSetAllocateInfo alloc_info {};\n   alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n   alloc_info.descriptorPool = data->descriptor_pool;\n   alloc_info.descriptorSetCount = 1;\n   alloc_info.pSetLayouts = &data->descriptor_layout;\n   VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,\n                                                       &alloc_info,\n                                                       &descriptor_set));\n\n   create_image(data, descriptor_set, width, height, format, image, image_mem, image_view);\n   return descriptor_set;\n}\n\nstatic void check_fonts(struct swapchain_data* data)\n{\n   struct device_data *device_data = data->device;\n   struct instance_data *instance_data = device_data->instance;\n   auto& params = instance_data->params;\n\n   if (params.font_params_hash != data->sw_stats.font_params_hash)\n   {\n      SPDLOG_DEBUG(\"Recreating font image\");\n      VkDescriptorSet desc_set = (VkDescriptorSet)data->font_atlas->TexID;\n      create_fonts(data->font_atlas, instance_data->params, data->sw_stats.font_small, data->sw_stats.font_text, data->sw_stats.font_secondary);\n      unsigned char* pixels;\n      int width, height;\n      data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height);\n\n      // wait for rendering to complete, if any\n      device_data->vtable.DeviceWaitIdle(device_data->device);\n      shutdown_swapchain_font(data);\n\n      if (desc_set)\n         create_image(data, desc_set, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view);\n      else\n         desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view);\n\n      data->font_atlas->SetTexID((ImTextureID)desc_set);\n      data->font_uploaded = false;\n      data->sw_stats.font_params_hash = params.font_params_hash;\n      SPDLOG_DEBUG(\"Default font tex size: {}x{}px\", width, height);\n   }\n}\n\nstatic void ensure_swapchain_fonts(struct swapchain_data *data,\n                                   VkCommandBuffer command_buffer)\n{\n   struct device_data *device_data = data->device;\n\n   check_fonts(data);\n\n   if (data->font_uploaded)\n      return;\n\n   data->font_uploaded = true;\n   unsigned char* pixels;\n   int width, height;\n   data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height);\n   size_t upload_size = width * height * 1 * sizeof(char);\n   upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image);\n}\n\nstatic void CreateOrResizeBuffer(struct device_data *data,\n                                 VkBuffer *buffer,\n                                 VkDeviceMemory *buffer_memory,\n                                 VkDeviceSize *buffer_size,\n                                 size_t new_size, VkBufferUsageFlagBits usage)\n{\n    if (*buffer != VK_NULL_HANDLE)\n        data->vtable.DestroyBuffer(data->device, *buffer, NULL);\n    if (*buffer_memory)\n        data->vtable.FreeMemory(data->device, *buffer_memory, NULL);\n\n    if (data->properties.limits.nonCoherentAtomSize > 0)\n    {\n      VkDeviceSize atom_size = data->properties.limits.nonCoherentAtomSize - 1;\n      new_size = (new_size + atom_size) & ~atom_size;\n    }\n\n    VkBufferCreateInfo buffer_info = {};\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = new_size;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    VK_CHECK(data->vtable.CreateBuffer(data->device, &buffer_info, NULL, buffer));\n\n    VkMemoryRequirements req;\n    data->vtable.GetBufferMemoryRequirements(data->device, *buffer, &req);\n    VkMemoryAllocateInfo alloc_info = {};\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = req.size;\n    alloc_info.memoryTypeIndex =\n       vk_memory_type(data, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);\n    VK_CHECK(data->vtable.AllocateMemory(data->device, &alloc_info, NULL, buffer_memory));\n\n    VK_CHECK(data->vtable.BindBufferMemory(data->device, *buffer, *buffer_memory, 0));\n    *buffer_size = new_size;\n}\n\nstatic struct overlay_draw *render_swapchain_display(struct swapchain_data *data,\n                                                     struct queue_data *present_queue,\n                                                     const VkSemaphore *wait_semaphores,\n                                                     unsigned n_wait_semaphores,\n                                                     unsigned image_index)\n{\n   auto saved_imgui_context = get_current_imgui_contexts();\n   make_imgui_contexts_current(data->imgui_contexts);\n\n   ImDrawData* draw_data = ImGui::GetDrawData();\n   struct device_data *device_data = data->device;\n\n   if (!draw_data || draw_data->TotalVtxCount == 0 || get_params()->no_display)\n   {\n      make_imgui_contexts_current(saved_imgui_context);\n      return nullptr;\n   }\n\n   struct overlay_draw *draw = get_overlay_draw(data, image_index);\n\n   device_data->vtable.ResetCommandBuffer(draw->command_buffer, 0);\n\n   VkRenderPassBeginInfo render_pass_info = {};\n   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n   render_pass_info.renderPass = data->render_pass;\n   render_pass_info.framebuffer = data->framebuffers[image_index];\n   render_pass_info.renderArea.extent.width = data->width;\n   render_pass_info.renderArea.extent.height = data->height;\n\n   VkCommandBufferBeginInfo buffer_begin_info = {};\n   buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n   device_data->vtable.BeginCommandBuffer(draw->command_buffer, &buffer_begin_info);\n\n   ensure_swapchain_fonts(data, draw->command_buffer);\n\n   /* Bounce the image to display back to color attachment layout for\n    * rendering on top of it.\n    */\n   VkImageMemoryBarrier imb;\n   imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n   imb.pNext = nullptr;\n   imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n   imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n   imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n   imb.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n   imb.image = data->images[image_index];\n   imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n   imb.subresourceRange.baseMipLevel = 0;\n   imb.subresourceRange.levelCount = 1;\n   imb.subresourceRange.baseArrayLayer = 0;\n   imb.subresourceRange.layerCount = 1;\n   imb.srcQueueFamilyIndex = present_queue->family_index;\n   imb.dstQueueFamilyIndex = device_data->graphic_queue->family_index;\n   device_data->vtable.CmdPipelineBarrier(draw->command_buffer,\n                                          VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n                                          VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n                                          0,          /* dependency flags */\n                                          0, nullptr, /* memory barriers */\n                                          0, nullptr, /* buffer memory barriers */\n                                          1, &imb);   /* image memory barriers */\n\n   device_data->vtable.CmdBeginRenderPass(draw->command_buffer, &render_pass_info,\n                                          VK_SUBPASS_CONTENTS_INLINE);\n\n   /* Create/Resize vertex & index buffers */\n   size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);\n   size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);\n   if (draw->vertex_buffer_size < vertex_size) {\n      CreateOrResizeBuffer(device_data,\n                           &draw->vertex_buffer,\n                           &draw->vertex_buffer_mem,\n                           &draw->vertex_buffer_size,\n                           vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);\n   }\n   if (draw->index_buffer_size < index_size) {\n      CreateOrResizeBuffer(device_data,\n                           &draw->index_buffer,\n                           &draw->index_buffer_mem,\n                           &draw->index_buffer_size,\n                           index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);\n   }\n\n   /* Upload vertex & index data */\n   ImDrawVert* vtx_dst = NULL;\n   ImDrawIdx* idx_dst = NULL;\n   VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem,\n                                          0, draw->vertex_buffer_size, 0, (void**)(&vtx_dst)));\n   VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem,\n                                          0, draw->index_buffer_size, 0, (void**)(&idx_dst)));\n   for (int n = 0; n < draw_data->CmdListsCount; n++)\n      {\n         const ImDrawList* cmd_list = draw_data->CmdLists[n];\n         memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));\n         memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));\n         vtx_dst += cmd_list->VtxBuffer.Size;\n         idx_dst += cmd_list->IdxBuffer.Size;\n      }\n   VkMappedMemoryRange range[2] = {};\n   range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n   range[0].memory = draw->vertex_buffer_mem;\n   range[0].size = VK_WHOLE_SIZE;\n   range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n   range[1].memory = draw->index_buffer_mem;\n   range[1].size = VK_WHOLE_SIZE;\n   VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range));\n   device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem);\n   device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem);\n\n   /* Bind pipeline and descriptor sets */\n   device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline);\n\n#if 1 // disable if using >1 font textures\n   VkDescriptorSet desc_set[1] = {\n      //data->descriptor_set\n      reinterpret_cast<VkDescriptorSet>(data->font_atlas->TexID)\n   };\n   device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                                             data->pipeline_layout, 0, 1, desc_set, 0, NULL);\n#endif\n\n   /* Bind vertex & index buffers */\n   VkBuffer vertex_buffers[1] = { draw->vertex_buffer };\n   VkDeviceSize vertex_offset[1] = { 0 };\n   device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset);\n   device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16);\n\n   /* Setup viewport */\n   VkViewport viewport;\n   viewport.x = 0;\n   viewport.y = 0;\n   viewport.width = draw_data->DisplaySize.x;\n   viewport.height = draw_data->DisplaySize.y;\n   viewport.minDepth = 0.0f;\n   viewport.maxDepth = 1.0f;\n   device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport);\n\n\n   /* Setup scale and translation through push constants :\n   *\n   * Our visible imgui space lies from draw_data->DisplayPos (top left) to\n   * draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin\n   * is typically (0,0) for single viewport apps.\n   */\n   float scale[2];\n   scale[0] = 2.0f / draw_data->DisplaySize.x;\n   scale[1] = 2.0f / draw_data->DisplaySize.y;\n   float translate[2];\n   translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0];\n   translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1];\n   device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,\n                                       VK_SHADER_STAGE_VERTEX_BIT,\n                                       sizeof(float) * 0, sizeof(float) * 2, scale);\n   device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout,\n                                       VK_SHADER_STAGE_VERTEX_BIT,\n                                       sizeof(float) * 2, sizeof(float) * 2, translate);\n\n   // Render the command lists:\n   int vtx_offset = 0;\n   int idx_offset = 0;\n   ImVec2 display_pos = draw_data->DisplayPos;\n   for (int n = 0; n < draw_data->CmdListsCount; n++)\n   {\n      const ImDrawList* cmd_list = draw_data->CmdLists[n];\n      for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n      {\n         const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n         // Apply scissor/clipping rectangle\n         // FIXME: We could clamp width/height based on clamped min/max values.\n         VkRect2D scissor;\n         scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;\n         scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;\n         scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);\n         scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?\n         device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor);\n#if 0 //enable if using >1 font textures or use texture array\n         VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };\n         device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                                                   data->pipeline_layout, 0, 1, desc_set, 0, NULL);\n#endif\n         // Draw\n         device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);\n\n         idx_offset += pcmd->ElemCount;\n      }\n      vtx_offset += cmd_list->VtxBuffer.Size;\n   }\n\n   device_data->vtable.CmdEndRenderPass(draw->command_buffer);\n\n   if (device_data->graphic_queue->family_index != present_queue->family_index)\n   {\n      /* Transfer the image back to the present queue family\n       * image layout was already changed to present by the render pass\n       */\n      imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n      imb.pNext = nullptr;\n      imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n      imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n      imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n      imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n      imb.image = data->images[image_index];\n      imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n      imb.subresourceRange.baseMipLevel = 0;\n      imb.subresourceRange.levelCount = 1;\n      imb.subresourceRange.baseArrayLayer = 0;\n      imb.subresourceRange.layerCount = 1;\n      imb.srcQueueFamilyIndex = device_data->graphic_queue->family_index;\n      imb.dstQueueFamilyIndex = present_queue->family_index;\n      device_data->vtable.CmdPipelineBarrier(draw->command_buffer,\n                                             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n                                             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,\n                                             0,          /* dependency flags */\n                                             0, nullptr, /* memory barriers */\n                                             0, nullptr, /* buffer memory barriers */\n                                             1, &imb);   /* image memory barriers */\n   }\n\n   device_data->vtable.EndCommandBuffer(draw->command_buffer);\n\n   /* When presenting on a different queue than where we're drawing the\n    * overlay *AND* when the application does not provide a semaphore to\n    * vkQueuePresent, insert our own cross engine synchronization\n    * semaphore.\n    */\n   if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) {\n      VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;\n      VkSubmitInfo submit_info = {};\n      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n      submit_info.commandBufferCount = 0;\n      submit_info.pWaitDstStageMask = &stages_wait;\n      submit_info.waitSemaphoreCount = 0;\n      submit_info.signalSemaphoreCount = 1;\n      submit_info.pSignalSemaphores = &draw->cross_engine_semaphore;\n\n      device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE);\n\n      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n      submit_info.commandBufferCount = 1;\n      submit_info.pWaitDstStageMask = &stages_wait;\n      submit_info.pCommandBuffers = &draw->command_buffer;\n      submit_info.waitSemaphoreCount = 1;\n      submit_info.pWaitSemaphores = &draw->cross_engine_semaphore;\n      submit_info.signalSemaphoreCount = 1;\n      submit_info.pSignalSemaphores = &draw->semaphore;\n\n      device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);\n   } else {\n      // wait in the fragment stage until the swapchain image is ready\n      std::vector<VkPipelineStageFlags> stages_wait(n_wait_semaphores, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);\n\n      VkSubmitInfo submit_info = {};\n      submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n      submit_info.commandBufferCount = 1;\n      submit_info.pCommandBuffers = &draw->command_buffer;\n      submit_info.pWaitDstStageMask = stages_wait.data();\n      submit_info.waitSemaphoreCount = n_wait_semaphores;\n      submit_info.pWaitSemaphores = wait_semaphores;\n      submit_info.signalSemaphoreCount = 1;\n      submit_info.pSignalSemaphores = &draw->semaphore;\n\n      device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence);\n   }\n\n   make_imgui_contexts_current(saved_imgui_context);\n   return draw;\n}\n\nstatic const uint32_t overlay_vert_spv[] = {\n#include \"overlay.vert.spv.h\"\n};\nstatic const uint32_t overlay_frag_spv[] = {\n#include \"overlay.frag.spv.h\"\n};\n\nstatic void setup_swapchain_data_pipeline(struct swapchain_data *data)\n{\n   struct device_data *device_data = data->device;\n   VkShaderModule vert_module, frag_module;\n\n   /* Create shader modules */\n   VkShaderModuleCreateInfo vert_info = {};\n   vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n   vert_info.codeSize = sizeof(overlay_vert_spv);\n   vert_info.pCode = overlay_vert_spv;\n   VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,\n                                                   &vert_info, NULL, &vert_module));\n   VkShaderModuleCreateInfo frag_info = {};\n   frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n   frag_info.codeSize = sizeof(overlay_frag_spv);\n   frag_info.pCode = (uint32_t*)overlay_frag_spv;\n   VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device,\n                                                   &frag_info, NULL, &frag_module));\n\n   /* Font sampler */\n   VkSamplerCreateInfo sampler_info = {};\n   sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n   sampler_info.magFilter = VK_FILTER_LINEAR;\n   sampler_info.minFilter = VK_FILTER_LINEAR;\n   sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n   sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n   sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n   sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n   sampler_info.minLod = -1000;\n   sampler_info.maxLod = 1000;\n   sampler_info.maxAnisotropy = 1.0f;\n   VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &sampler_info,\n                                              NULL, &data->font_sampler));\n\n   /* Descriptor pool */\n   VkDescriptorPoolSize sampler_pool_size = {};\n   sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n   sampler_pool_size.descriptorCount = 1;\n   VkDescriptorPoolCreateInfo desc_pool_info = {};\n   desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n   desc_pool_info.maxSets = 1;\n   desc_pool_info.poolSizeCount = 1;\n   desc_pool_info.pPoolSizes = &sampler_pool_size;\n   VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device,\n                                                     &desc_pool_info,\n                                                     NULL, &data->descriptor_pool));\n\n   /* Descriptor layout */\n   VkSampler sampler[1] = { data->font_sampler };\n   VkDescriptorSetLayoutBinding binding[1] = {};\n   binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n   binding[0].descriptorCount = 1;\n   binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n   binding[0].pImmutableSamplers = sampler;\n   VkDescriptorSetLayoutCreateInfo set_layout_info = {};\n   set_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n   set_layout_info.bindingCount = 1;\n   set_layout_info.pBindings = binding;\n   VK_CHECK(device_data->vtable.CreateDescriptorSetLayout(device_data->device,\n                                                          &set_layout_info,\n                                                          NULL, &data->descriptor_layout));\n\n   /* Descriptor set */\n/*\n   VkDescriptorSetAllocateInfo alloc_info = {};\n   alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n   alloc_info.descriptorPool = data->descriptor_pool;\n   alloc_info.descriptorSetCount = 1;\n   alloc_info.pSetLayouts = &data->descriptor_layout;\n   VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,\n                                                       &alloc_info,\n                                                       &data->descriptor_set));\n*/\n\n   /* Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full\n    * 3d projection matrix\n    */\n   VkPushConstantRange push_constants[1] = {};\n   push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n   push_constants[0].offset = sizeof(float) * 0;\n   push_constants[0].size = sizeof(float) * 4;\n   VkPipelineLayoutCreateInfo layout_info = {};\n   layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n   layout_info.setLayoutCount = 1;\n   layout_info.pSetLayouts = &data->descriptor_layout;\n   layout_info.pushConstantRangeCount = 1;\n   layout_info.pPushConstantRanges = push_constants;\n   VK_CHECK(device_data->vtable.CreatePipelineLayout(device_data->device,\n                                                     &layout_info,\n                                                     NULL, &data->pipeline_layout));\n\n   VkPipelineShaderStageCreateInfo stage[2] = {};\n   stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n   stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT;\n   stage[0].module = vert_module;\n   stage[0].pName = \"main\";\n   stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n   stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;\n   stage[1].module = frag_module;\n   stage[1].pName = \"main\";\n\n   VkVertexInputBindingDescription binding_desc[1] = {};\n   binding_desc[0].stride = sizeof(ImDrawVert);\n   binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n   VkVertexInputAttributeDescription attribute_desc[3] = {};\n   attribute_desc[0].location = 0;\n   attribute_desc[0].binding = binding_desc[0].binding;\n   attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT;\n   attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos);\n   attribute_desc[1].location = 1;\n   attribute_desc[1].binding = binding_desc[0].binding;\n   attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT;\n   attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv);\n   attribute_desc[2].location = 2;\n   attribute_desc[2].binding = binding_desc[0].binding;\n   attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM;\n   attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col);\n\n   VkPipelineVertexInputStateCreateInfo vertex_info = {};\n   vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n   vertex_info.vertexBindingDescriptionCount = 1;\n   vertex_info.pVertexBindingDescriptions = binding_desc;\n   vertex_info.vertexAttributeDescriptionCount = 3;\n   vertex_info.pVertexAttributeDescriptions = attribute_desc;\n\n   VkPipelineInputAssemblyStateCreateInfo ia_info = {};\n   ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n   ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n\n   VkPipelineViewportStateCreateInfo viewport_info = {};\n   viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n   viewport_info.viewportCount = 1;\n   viewport_info.scissorCount = 1;\n\n   VkPipelineRasterizationStateCreateInfo raster_info = {};\n   raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n   raster_info.polygonMode = VK_POLYGON_MODE_FILL;\n   raster_info.cullMode = VK_CULL_MODE_NONE;\n   raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n   raster_info.lineWidth = 1.0f;\n\n   VkPipelineMultisampleStateCreateInfo ms_info = {};\n   ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n   ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n   VkPipelineColorBlendAttachmentState color_attachment[1] = {};\n   color_attachment[0].blendEnable = VK_TRUE;\n   color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;\n   color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n   color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD;\n   color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;\n   color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n   color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;\n   color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT |\n      VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;\n\n   VkPipelineDepthStencilStateCreateInfo depth_info = {};\n   depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;\n\n   VkPipelineColorBlendStateCreateInfo blend_info = {};\n   blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n   blend_info.attachmentCount = 1;\n   blend_info.pAttachments = color_attachment;\n\n   VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };\n   VkPipelineDynamicStateCreateInfo dynamic_state = {};\n   dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n   dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states);\n   dynamic_state.pDynamicStates = dynamic_states;\n\n   VkGraphicsPipelineCreateInfo info = {};\n   info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n   info.flags = 0;\n   info.stageCount = 2;\n   info.pStages = stage;\n   info.pVertexInputState = &vertex_info;\n   info.pInputAssemblyState = &ia_info;\n   info.pViewportState = &viewport_info;\n   info.pRasterizationState = &raster_info;\n   info.pMultisampleState = &ms_info;\n   info.pDepthStencilState = &depth_info;\n   info.pColorBlendState = &blend_info;\n   info.pDynamicState = &dynamic_state;\n   info.layout = data->pipeline_layout;\n   info.renderPass = data->render_pass;\n   VK_CHECK(\n      device_data->vtable.CreateGraphicsPipelines(device_data->device, VK_NULL_HANDLE,\n                                                  1, &info,\n                                                  NULL, &data->pipeline));\n\n   device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL);\n   device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL);\n\n   check_fonts(data);\n\n//   if (data->descriptor_set)\n//      update_image_descriptor(data, data->font_image_view[0], data->descriptor_set);\n}\n\nstatic void convert_colors_vk(VkFormat format, VkColorSpaceKHR colorspace, struct swapchain_stats& sw_stats, struct overlay_params& params)\n{\n   /* TODO: Support more colorspacess */\n   switch (colorspace) {\n      case VK_COLOR_SPACE_HDR10_ST2084_EXT:\n         params.transfer_function = PQ;\n         break;\n      case VK_COLOR_SPACE_HDR10_HLG_EXT:\n         params.transfer_function = HLG;\n         break;\n      case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:\n         params.transfer_function = SRGB;\n         break;\n      /* use no conversion for rest of the colorspaces */\n      default:\n         params.transfer_function = NONE;\n         break;\n   }\n\n   if (params.transfer_function == NONE)\n   {\n      switch (format) {\n         case VK_FORMAT_R8_SRGB:\n         case VK_FORMAT_R8G8_SRGB:\n         case VK_FORMAT_R8G8B8_SRGB:\n         case VK_FORMAT_B8G8R8_SRGB:\n         case VK_FORMAT_R8G8B8A8_SRGB:\n         case VK_FORMAT_B8G8R8A8_SRGB:\n         case VK_FORMAT_A8B8G8R8_SRGB_PACK32:\n         case VK_FORMAT_BC1_RGB_SRGB_BLOCK:\n         case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:\n         case VK_FORMAT_BC2_SRGB_BLOCK:\n         case VK_FORMAT_BC3_SRGB_BLOCK:\n         case VK_FORMAT_BC7_SRGB_BLOCK:\n         case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:\n         case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:\n         case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:\n         case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:\n         case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:\n         case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:\n         case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:\n         case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:\n            params.transfer_function = SRGB;\n            break;\n         default: break;\n      }\n   }\n\n   HUDElements.convert_colors(params.transfer_function != NONE, params);\n}\n\nstatic void setup_swapchain_data(struct swapchain_data *data,\n                                 const VkSwapchainCreateInfoKHR *pCreateInfo)\n{\n   struct device_data *device_data = data->device;\n   data->width = pCreateInfo->imageExtent.width;\n   data->height = pCreateInfo->imageExtent.height;\n   data->format = pCreateInfo->imageFormat;\n\n   if (!data->imgui_contexts.imgui)\n      data->imgui_contexts = create_imgui_contexts(data->font_atlas);\n   auto saved_imgui_contexts = get_current_imgui_contexts();\n   make_imgui_contexts_current(data->imgui_contexts);\n\n   ImGui::GetIO().IniFilename = NULL;\n   ImGui::GetIO().DisplaySize = ImVec2((float)data->width, (float)data->height);\n   convert_colors_vk(pCreateInfo->imageFormat, pCreateInfo->imageColorSpace, data->sw_stats, device_data->instance->params);\n\n   /* Render pass */\n   VkAttachmentDescription attachment_desc = {};\n   attachment_desc.format = pCreateInfo->imageFormat;\n   attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT;\n   attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n   attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n   attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n   attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n   attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n   attachment_desc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n   VkAttachmentReference color_attachment = {};\n   color_attachment.attachment = 0;\n   color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n   VkSubpassDescription subpass = {};\n   subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n   subpass.colorAttachmentCount = 1;\n   subpass.pColorAttachments = &color_attachment;\n   VkSubpassDependency dependency = {};\n   dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n   dependency.dstSubpass = 0;\n   dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n   dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n   dependency.srcAccessMask = 0;\n   dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n   VkRenderPassCreateInfo render_pass_info = {};\n   render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n   render_pass_info.attachmentCount = 1;\n   render_pass_info.pAttachments = &attachment_desc;\n   render_pass_info.subpassCount = 1;\n   render_pass_info.pSubpasses = &subpass;\n   render_pass_info.dependencyCount = 1;\n   render_pass_info.pDependencies = &dependency;\n   VK_CHECK(device_data->vtable.CreateRenderPass(device_data->device,\n                                                 &render_pass_info,\n                                                 NULL, &data->render_pass));\n\n   setup_swapchain_data_pipeline(data);\n\n   uint32_t n_images = 0;\n   VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,\n                                                      data->swapchain,\n                                                      &n_images,\n                                                      NULL));\n\n   data->images.resize(n_images);\n   data->image_views.resize(n_images);\n   data->framebuffers.resize(n_images);\n\n   VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device,\n                                                      data->swapchain,\n                                                      &n_images,\n                                                      data->images.data()));\n\n\n   if (n_images != data->images.size()) {\n      data->images.resize(n_images);\n      data->image_views.resize(n_images);\n      data->framebuffers.resize(n_images);\n   }\n\n   /* Image views */\n   VkImageViewCreateInfo view_info = {};\n   view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n   view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n   view_info.format = pCreateInfo->imageFormat;\n   view_info.components.r = VK_COMPONENT_SWIZZLE_R;\n   view_info.components.g = VK_COMPONENT_SWIZZLE_G;\n   view_info.components.b = VK_COMPONENT_SWIZZLE_B;\n   view_info.components.a = VK_COMPONENT_SWIZZLE_A;\n   view_info.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };\n   for (size_t i = 0; i < data->images.size(); i++) {\n      view_info.image = data->images[i];\n      VK_CHECK(device_data->vtable.CreateImageView(device_data->device,\n                                                   &view_info, NULL,\n                                                   &data->image_views[i]));\n   }\n\n   /* Framebuffers */\n   VkImageView attachment[1];\n   VkFramebufferCreateInfo fb_info = {};\n   fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n   fb_info.renderPass = data->render_pass;\n   fb_info.attachmentCount = 1;\n   fb_info.pAttachments = attachment;\n   fb_info.width = data->width;\n   fb_info.height = data->height;\n   fb_info.layers = 1;\n   for (size_t i = 0; i < data->image_views.size(); i++) {\n      attachment[0] = data->image_views[i];\n      VK_CHECK(device_data->vtable.CreateFramebuffer(device_data->device, &fb_info,\n                                                     NULL, &data->framebuffers[i]));\n   }\n\n   /* Command buffer pool */\n   VkCommandPoolCreateInfo cmd_buffer_pool_info = {};\n   cmd_buffer_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n   cmd_buffer_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n   cmd_buffer_pool_info.queueFamilyIndex = device_data->graphic_queue->family_index;\n   VK_CHECK(device_data->vtable.CreateCommandPool(device_data->device,\n                                                  &cmd_buffer_pool_info,\n                                                  NULL, &data->command_pool));\n\n   make_imgui_contexts_current(saved_imgui_contexts);\n}\n\nstatic void shutdown_swapchain_font(struct swapchain_data *data)\n{\n   struct device_data *device_data = data->device;\n\n   device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL);\n   device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL);\n   device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL);\n\n   device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL);\n   device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL);\n}\n\nstatic void shutdown_swapchain_data(struct swapchain_data *data)\n{\n   struct device_data *device_data = data->device;\n\n   for (auto draw : data->draws) {\n      if (!draw) continue;\n      device_data->vtable.FreeCommandBuffers(device_data->device, data->command_pool, 1, &draw->command_buffer);\n      device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL);\n      device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL);\n      device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL);\n      device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL);\n      device_data->vtable.DestroyBuffer(device_data->device, draw->index_buffer, NULL);\n      device_data->vtable.FreeMemory(device_data->device, draw->vertex_buffer_mem, NULL);\n      device_data->vtable.FreeMemory(device_data->device, draw->index_buffer_mem, NULL);\n      delete draw;\n   }\n\n   for (size_t i = 0; i < data->images.size(); i++) {\n      device_data->vtable.DestroyImageView(device_data->device, data->image_views[i], NULL);\n      device_data->vtable.DestroyFramebuffer(device_data->device, data->framebuffers[i], NULL);\n   }\n\n   device_data->vtable.DestroyRenderPass(device_data->device, data->render_pass, NULL);\n\n   device_data->vtable.DestroyCommandPool(device_data->device, data->command_pool, NULL);\n\n   device_data->vtable.DestroyPipeline(device_data->device, data->pipeline, NULL);\n   device_data->vtable.DestroyPipelineLayout(device_data->device, data->pipeline_layout, NULL);\n\n   device_data->vtable.DestroyDescriptorPool(device_data->device,\n                                             data->descriptor_pool, NULL);\n   device_data->vtable.DestroyDescriptorSetLayout(device_data->device,\n                                                  data->descriptor_layout, NULL);\n\n   device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);\n   shutdown_swapchain_font(data);\n\n   IM_DELETE(data->font_atlas);\n   destroy_imgui_contexts(data->imgui_contexts);\n}\n\nstatic struct overlay_draw *before_present(struct swapchain_data *swapchain_data,\n                                           struct queue_data *present_queue,\n                                           const VkSemaphore *wait_semaphores,\n                                           unsigned n_wait_semaphores,\n                                           unsigned imageIndex)\n{\n   struct overlay_draw *draw = NULL;\n\n   snapshot_swapchain_frame(swapchain_data);\n\n   if (swapchain_data->sw_stats.n_frames > 0) {\n      compute_swapchain_display(swapchain_data);\n      draw = render_swapchain_display(swapchain_data, present_queue,\n                                      wait_semaphores, n_wait_semaphores,\n                                      imageIndex);\n   }\n\n   return draw;\n}\n\nstatic bool is_present_mode_supported(VkPhysicalDevice device, VkSurfaceKHR surface, VkPresentModeKHR targetPresentMode)\n{\n   struct instance_data *instance_data = FIND(struct instance_data, device);\n\n   PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR =\n   (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) instance_data->vtable.GetInstanceProcAddr(instance_data->instance, \"vkGetPhysicalDeviceSurfacePresentModesKHR\");\n\n   if (fpGetPhysicalDeviceSurfacePresentModesKHR != NULL) {\n      uint32_t presentModeCount = 0;\n      VkResult result;\n      result = fpGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, NULL);\n      if (result != VK_SUCCESS) {\n         SPDLOG_ERROR(\"Failed to get presentModeCount: vkGetPhysicalDeviceSurfacePresentModesKHR with {}\", vk_Result_to_str(result));\n         return false;\n      }\n      std::vector<VkPresentModeKHR> presentModes(presentModeCount);\n      presentModes.resize(presentModeCount);\n      result = fpGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data());\n\n      if (result == VK_SUCCESS) {\n         for (const auto& mode : presentModes)\n            if (mode == targetPresentMode)\n               return true;\n      }\n      else {\n         SPDLOG_ERROR(\"Failed to get presentModes: vkGetPhysicalDeviceSurfacePresentModesKHR failed with {}\", vk_Result_to_str(result));\n      }\n   }\n   return false;\n}\n\nstatic VkResult overlay_CreateSwapchainKHR(\n    VkDevice                                    device,\n    const VkSwapchainCreateInfoKHR*             pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkSwapchainKHR*                             pSwapchain)\n{\n   VkSwapchainCreateInfoKHR createInfo = *pCreateInfo;\n\n   createInfo.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n\n   struct device_data *device_data = FIND(struct device_data, device);\n   const auto& params = device_data->instance->params;\n\n   std::optional<VkPresentModeKHR> target_present_mode;\n   if (params.m_vulkan_present_mode.has_value()) {\n      target_present_mode = params.m_vulkan_present_mode;\n   }\n\n   if (target_present_mode.has_value()) {\n      if (is_present_mode_supported(device_data->physical_device, createInfo.surface, target_present_mode.value())) {\n         createInfo.presentMode = target_present_mode.value();\n      }\n      else {\n         SPDLOG_WARN(\"Present mode is not supported: {}\", string_VkPresentModeKHR(target_present_mode.value()));\n      }\n   }\n\n   HUDElements.cur_present_mode = createInfo.presentMode;\n   SPDLOG_DEBUG(\"Present mode : {}\", string_VkPresentModeKHR(HUDElements.cur_present_mode));\n\n   VkResult result = device_data->vtable.CreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain);\n   if (result != VK_SUCCESS) return result;\n   struct swapchain_data *swapchain_data = new_swapchain_data(*pSwapchain, device_data);\n   setup_swapchain_data(swapchain_data, pCreateInfo);\n\n   const VkPhysicalDeviceProperties& prop = device_data->properties;\n   swapchain_data->sw_stats.version_vk.major = VK_VERSION_MAJOR(prop.apiVersion);\n   swapchain_data->sw_stats.version_vk.minor = VK_VERSION_MINOR(prop.apiVersion);\n   swapchain_data->sw_stats.version_vk.patch = VK_VERSION_PATCH(prop.apiVersion);\n   swapchain_data->sw_stats.engineName    = device_data->instance->engineName;\n   swapchain_data->sw_stats.engineVersion = device_data->instance->engineVersion;\n   swapchain_data->sw_stats.engine        = device_data->instance->engine;\n   swapchain_data->sw_stats.applicationVersion = device_data->instance->applicationVersion;\n\n   HUDElements.vendorID = prop.vendorID;\n   std::stringstream ss;\n//   ss << prop.deviceName;\n   if (prop.vendorID == 0x10de) {\n      ss << \" \" << ((prop.driverVersion >> 22) & 0x3ff);\n      ss << \".\"  << ((prop.driverVersion >> 14) & 0x0ff);\n      ss << \".\"  << std::setw(2) << std::setfill('0') << ((prop.driverVersion >> 6) & 0x0ff);\n   }\n#ifdef _WIN32\n    else if (prop.vendorID == 0x8086) {\n      ss << \" \" << (prop.driverVersion >> 14);\n      ss << \".\"  << (prop.driverVersion & 0x3fff);\n   }\n#endif\n   else {\n      ss << \" \" << VK_VERSION_MAJOR(prop.driverVersion);\n      ss << \".\" << VK_VERSION_MINOR(prop.driverVersion);\n      ss << \".\" << VK_VERSION_PATCH(prop.driverVersion);\n   }\n   std::string driverVersion = ss.str();\n\n   std::string deviceName = prop.deviceName;\n   if (!is_blacklisted()) {\n#ifdef __linux__\n      swapchain_data->sw_stats.gpuName = remove_parentheses(deviceName);\n#endif\n   }\n   swapchain_data->sw_stats.driverName = driverProps.driverInfo;\n\n   return result;\n}\n\nstatic void overlay_DestroySwapchainKHR(\n    VkDevice                                    device,\n    VkSwapchainKHR                              swapchain,\n    const VkAllocationCallbacks*                pAllocator)\n{\n   if (swapchain == VK_NULL_HANDLE) {\n      struct device_data *device_data = FIND(struct device_data, device);\n      device_data->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);\n      return;\n   }\n\n   struct swapchain_data *swapchain_data =\n      FIND(struct swapchain_data, swapchain);\n\n   shutdown_swapchain_data(swapchain_data);\n   swapchain_data->device->vtable.DestroySwapchainKHR(device, swapchain, pAllocator);\n   destroy_swapchain_data(swapchain_data);\n}\n\nstatic VkResult overlay_QueuePresentKHR(\n    VkQueue                                     queue,\n    const VkPresentInfoKHR*                     pPresentInfo)\n{\n   if (fps_limiter)\n      fps_limiter->limit(true);\n\n   struct queue_data *queue_data = FIND(struct queue_data, queue);\n\n   /* Otherwise we need to add our overlay drawing semaphore to the list of\n    * semaphores to wait on. If we don't do that the presented picture might\n    * be have incomplete overlay drawings.\n    */\n   VkResult result = VK_SUCCESS;\n   for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {\n      VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i];\n      struct swapchain_data *swapchain_data =\n         FIND(struct swapchain_data, swapchain);\n\n      uint32_t image_index = pPresentInfo->pImageIndices[i];\n\n      VkPresentInfoKHR present_info = *pPresentInfo;\n      present_info.swapchainCount = 1;\n      present_info.pSwapchains = &swapchain;\n      present_info.pImageIndices = &image_index;\n\n      VkBaseInStructure **mode_info_node = vk_find_next_struct(\n          (void**)&present_info.pNext, VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT);\n\n      VkSwapchainPresentModeInfoEXT mode_info_patched;\n      VkPresentModeKHR present_mode_override;\n\n      if (mode_info_node) {\n         const auto *mode_info = (const VkSwapchainPresentModeInfoEXT *)*mode_info_node;\n         HUDElements.cur_present_mode = mode_info->pPresentModes[i];\n\n         // Check if there is a user-specified present mode override.\n         if (get_params()->m_vulkan_present_mode.has_value()) {\n            present_mode_override = get_params()->m_vulkan_present_mode.value();\n\n            // Patch `mode_info` so that the user-specified override is not\n            // clobbered by the application from swapchain maintenance.\n            mode_info_patched = *mode_info;\n            mode_info_patched.swapchainCount = 1;\n            mode_info_patched.pPresentModes = &present_mode_override;\n            *mode_info_node = (VkBaseInStructure *)&mode_info_patched;\n\n            HUDElements.cur_present_mode = present_mode_override;\n        }\n      }\n\n      struct overlay_draw *draw = before_present(swapchain_data,\n                                                   queue_data,\n                                                   pPresentInfo->pWaitSemaphores,\n                                                   i == 0 ? pPresentInfo->waitSemaphoreCount : 0,\n                                                   image_index);\n\n      /* Because the submission of the overlay draw waits on the semaphores\n         * handed for present, we don't need to have this present operation\n         * wait on them as well, we can just wait on the overlay submission\n         * semaphore.\n         */\n      if (draw) {\n         present_info.pWaitSemaphores = &draw->semaphore;\n         present_info.waitSemaphoreCount = 1;\n      }\n\n      VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);\n      if (pPresentInfo->pResults)\n         pPresentInfo->pResults[i] = chain_result;\n      if (chain_result != VK_SUCCESS && result == VK_SUCCESS)\n         result = chain_result;\n   }\n\n   if (fps_limiter)\n      fps_limiter->limit(false);\n\n   return result;\n}\n\nstatic VkResult overlay_BeginCommandBuffer(\n    VkCommandBuffer                             commandBuffer,\n    const VkCommandBufferBeginInfo*             pBeginInfo)\n{\n   struct command_buffer_data *cmd_buffer_data =\n      FIND(struct command_buffer_data, commandBuffer);\n   struct device_data *device_data = cmd_buffer_data->device;\n\n   /* Otherwise record a begin query as first command. */\n   VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo);\n\n   return result;\n}\n\nstatic VkResult overlay_EndCommandBuffer(\n    VkCommandBuffer                             commandBuffer)\n{\n   struct command_buffer_data *cmd_buffer_data =\n      FIND(struct command_buffer_data, commandBuffer);\n   struct device_data *device_data = cmd_buffer_data->device;\n\n   return device_data->vtable.EndCommandBuffer(commandBuffer);\n}\n\nstatic VkResult overlay_ResetCommandBuffer(\n    VkCommandBuffer                             commandBuffer,\n    VkCommandBufferResetFlags                   flags)\n{\n   struct command_buffer_data *cmd_buffer_data =\n      FIND(struct command_buffer_data, commandBuffer);\n   struct device_data *device_data = cmd_buffer_data->device;\n\n   return device_data->vtable.ResetCommandBuffer(commandBuffer, flags);\n}\n\nstatic void overlay_CmdExecuteCommands(\n    VkCommandBuffer                             commandBuffer,\n    uint32_t                                    commandBufferCount,\n    const VkCommandBuffer*                      pCommandBuffers)\n{\n   struct command_buffer_data *cmd_buffer_data =\n      FIND(struct command_buffer_data, commandBuffer);\n   struct device_data *device_data = cmd_buffer_data->device;\n\n   device_data->vtable.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);\n}\n\nstatic VkResult overlay_AllocateCommandBuffers(\n   VkDevice                           device,\n   const VkCommandBufferAllocateInfo* pAllocateInfo,\n   VkCommandBuffer*                   pCommandBuffers)\n{\n   struct device_data *device_data = FIND(struct device_data, device);\n   VkResult result =\n      device_data->vtable.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers);\n   if (result != VK_SUCCESS)\n      return result;\n\n   for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {\n      new_command_buffer_data(pCommandBuffers[i], pAllocateInfo->level,\n                              device_data);\n   }\n\n   return result;\n}\n\nstatic void overlay_FreeCommandBuffers(\n   VkDevice               device,\n   VkCommandPool          commandPool,\n   uint32_t               commandBufferCount,\n   const VkCommandBuffer* pCommandBuffers)\n{\n   struct device_data *device_data = FIND(struct device_data, device);\n   for (uint32_t i = 0; i < commandBufferCount; i++) {\n      struct command_buffer_data *cmd_buffer_data =\n         FIND(struct command_buffer_data, pCommandBuffers[i]);\n\n      /* It is legal to free a NULL command buffer*/\n      if (!cmd_buffer_data)\n         continue;\n\n      destroy_command_buffer_data(cmd_buffer_data);\n   }\n\n   device_data->vtable.FreeCommandBuffers(device, commandPool,\n                                          commandBufferCount, pCommandBuffers);\n}\n\nstatic VkResult overlay_QueueSubmit(\n    VkQueue                                     queue,\n    uint32_t                                    submitCount,\n    const VkSubmitInfo*                         pSubmits,\n    VkFence                                     fence)\n{\n   struct queue_data *queue_data = FIND(struct queue_data, queue);\n   struct device_data *device_data = queue_data->device;\n\n   return device_data->vtable.QueueSubmit(queue, submitCount, pSubmits, fence);\n}\n\nstatic VkResult overlay_CreateDevice(\n    VkPhysicalDevice                            physicalDevice,\n    const VkDeviceCreateInfo*                   pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkDevice*                                   pDevice)\n{\n   struct instance_data *instance_data =\n      FIND(struct instance_data, physicalDevice);\n   VkLayerDeviceCreateInfo *chain_info =\n      get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);\n\n   assert(chain_info->u.pLayerInfo);\n   PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;\n   PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;\n   PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, \"vkCreateDevice\");\n   if (fpCreateDevice == NULL) {\n      return VK_ERROR_INITIALIZATION_FAILED;\n   }\n\n   // Advance the link info for the next element on the chain\n   chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;\n\n\n   std::vector<const char*> enabled_extensions(pCreateInfo->ppEnabledExtensionNames,\n                                               pCreateInfo->ppEnabledExtensionNames +\n                                               pCreateInfo->enabledExtensionCount);\n\n   uint32_t extension_count;\n\n   instance_data->pd_vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, nullptr);\n\n   std::vector<VkExtensionProperties> available_extensions(extension_count);\n   instance_data->pd_vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, available_extensions.data());\n\n   auto has_extension = [](const auto& list, const char *name) {\n      return std::any_of(list.begin(), list.end(), [&](const auto& e) {\n         return e == std::string_view(name);\n      });\n   };\n\n\n   bool can_get_driver_info = false;\n\n   for (auto& extension : available_extensions) {\n      if (extension.extensionName == std::string_view(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) {\n         can_get_driver_info = true;\n         if (instance_data->api_version < VK_API_VERSION_1_2) {\n            if (!has_extension(enabled_extensions, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) {\n               enabled_extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME);\n            }\n         }\n      }\n      if (extension.extensionName == std::string_view(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) {\n         if (!has_extension(enabled_extensions, VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) {\n            enabled_extensions.push_back(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME);\n         }\n      }\n   }\n\n   VkDeviceCreateInfo pCreateInfoPatched = *pCreateInfo;\n   pCreateInfoPatched.ppEnabledExtensionNames = enabled_extensions.data();\n   pCreateInfoPatched.enabledExtensionCount = (uint32_t) enabled_extensions.size();\n\n   VkResult result = fpCreateDevice(physicalDevice, &pCreateInfoPatched, pAllocator, pDevice);\n   if (result != VK_SUCCESS) return result;\n\n   struct device_data *device_data = new_device_data(*pDevice, instance_data);\n   vk_device_dispatch_table_load(&device_data->vtable,\n                              fpGetDeviceProcAddr, *pDevice);\n   device_data->physical_device = physicalDevice;\n   vk_instance_dispatch_table_load(&instance_data->vtable,\n                                   fpGetInstanceProcAddr,\n                                   instance_data->instance);\n\n   instance_data->pd_vtable.GetPhysicalDeviceProperties(device_data->physical_device,\n                                                     &device_data->properties);\n\n   VkLayerDeviceCreateInfo *load_data_info =\n      get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK);\n   device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData;\n\n   driverProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;\n   driverProps.pNext = nullptr;\n   if (can_get_driver_info) {\n      VkPhysicalDeviceProperties2 deviceProps = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &driverProps};\n      instance_data->pd_vtable.GetPhysicalDeviceProperties2(device_data->physical_device, &deviceProps);\n   }\n\n   if (!is_blacklisted()) {\n      device_map_queues(device_data, pCreateInfo);\n#ifdef __linux__\n      gpu = device_data->properties.deviceName;\n      SPDLOG_DEBUG(\"gpu: {}\", gpu);\n#endif\n   }\n\n   return result;\n}\n\nstatic void overlay_DestroyDevice(\n    VkDevice                                    device,\n    const VkAllocationCallbacks*                pAllocator)\n{\n   struct device_data *device_data = FIND(struct device_data, device);\n   if (!is_blacklisted())\n      device_unmap_queues(device_data);\n   device_data->vtable.DestroyDevice(device, pAllocator);\n   destroy_device_data(device_data);\n}\n\nstatic VkResult overlay_CreateInstance(\n    const VkInstanceCreateInfo*                 pCreateInfo,\n    const VkAllocationCallbacks*                pAllocator,\n    VkInstance*                                 pInstance)\n{\n   VkLayerInstanceCreateInfo *chain_info =\n      get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);\n\n   std::string engineVersion, engineName;\n   enum EngineTypes engine = EngineTypes::UNKNOWN;\n   const char* pEngineName = nullptr;\n\n   struct instance_data *instance_data = new_instance_data(*pInstance);\n   if (pCreateInfo->pApplicationInfo) {\n      pEngineName = pCreateInfo->pApplicationInfo->pEngineName;\n      instance_data->applicationVersion = pCreateInfo->pApplicationInfo->applicationVersion;\n   }\n   if (pEngineName)\n   {\n      engineName = pEngineName;\n      global_engine_name = engineName;\n   }\n   if (!is_blacklisted(true)) {\n      if (engineName == \"DXVK\" || engineName == \"vkd3d\") {\n         int engineVer = pCreateInfo->pApplicationInfo->engineVersion;\n         engineVersion = to_string(VK_VERSION_MAJOR(engineVer)) + \".\" + to_string(VK_VERSION_MINOR(engineVer)) + \".\" + to_string(VK_VERSION_PATCH(engineVer));\n      }\n\n      if (engineName == \"DXVK\")\n         engine = DXVK;\n\n      else if (engineName == \"vkd3d\")\n         engine = VKD3D;\n\n      else if(engineName == \"mesa zink\") {\n         engine = ZINK;\n      }\n\n      else if (engineName == \"Damavand\")\n         engine = DAMAVAND;\n\n      else if (engineName == \"Feral3D\")\n         engine = FERAL3D;\n\n      else if (engineName == \"SDLGPU\")\n         engine = SDL;\n\n      else\n         engine = VULKAN;\n   }\n\n   assert(chain_info->u.pLayerInfo);\n   PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr =\n      chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;\n   PFN_vkCreateInstance fpCreateInstance =\n      (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, \"vkCreateInstance\");\n   if (fpCreateInstance == NULL) {\n      return VK_ERROR_INITIALIZATION_FAILED;\n   }\n\n   // Advance the link info for the next element on the chain\n   chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;\n\n\n   VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);\n   if (result != VK_SUCCESS) return result;\n   vk_instance_dispatch_table_load(&instance_data->vtable,\n                                   fpGetInstanceProcAddr,\n                                   instance_data->instance);\n   vk_physical_device_dispatch_table_load(&instance_data->pd_vtable,\n                                          fpGetInstanceProcAddr,\n                                          instance_data->instance);\n   instance_data_map_physical_devices(instance_data, true);\n\n   if (is_blacklisted())\n      return result;\n\n   parse_overlay_config(&instance_data->params, getenv(\"MANGOHUD_CONFIG\"), false);\n   //check for blacklist item in the config file\n   for (auto& item : instance_data->params.blacklist) {\n      add_blacklist(item);\n   }\n\n   if (!is_blacklisted()) {\n#ifdef __linux__\n      init_system_info();\n      instance_data->notifier.params = &instance_data->params;\n      start_notifier(instance_data->notifier);\n#endif\n\n      init_cpu_stats(instance_data->params);\n\n      instance_data->engine = engine;\n      instance_data->engineName = engineName;\n      instance_data->engineVersion = engineVersion;\n   }\n\n   instance_data->api_version = pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0;\n\n   return result;\n}\n\nstatic VkResult overlay_CreateSampler(\n\tVkDevice                     device,\n\tconst VkSamplerCreateInfo*   pCreateInfo,\n\tconst VkAllocationCallbacks* pAllocator,\n\tVkSampler*                   pSampler)\n{\n   struct device_data *device_data = FIND(struct device_data, device);\n   auto params = device_data->instance->params;\n\tVkSamplerCreateInfo sampler = *pCreateInfo;\n\n   if (params.picmip > -17 && params.picmip < 17)\n      sampler.mipLodBias = params.picmip;\n\n   if (params.af > 0){\n      sampler.anisotropyEnable = VK_TRUE;\n      sampler.maxAnisotropy = params.af;\n   } else if (params.af == 0)\n      sampler.anisotropyEnable = VK_FALSE;\n\n   if (params.enabled[OVERLAY_PARAM_ENABLED_trilinear]){\n      sampler.magFilter = VK_FILTER_LINEAR;\n      sampler.minFilter = VK_FILTER_LINEAR;\n      sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n   }\n\n   if (params.enabled[OVERLAY_PARAM_ENABLED_bicubic]){\n      sampler.magFilter = VK_FILTER_CUBIC_IMG;\n      sampler.minFilter = VK_FILTER_CUBIC_IMG;\n      sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n   }\n\n   if (params.enabled[OVERLAY_PARAM_ENABLED_retro]){\n      sampler.magFilter = VK_FILTER_NEAREST;\n      sampler.minFilter = VK_FILTER_NEAREST;\n      sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n   }\n\n\tVkResult result = device_data->vtable.CreateSampler(device, &sampler, pAllocator, pSampler);\n\n\treturn result;\n}\n\nstatic void overlay_DestroyInstance(\n    VkInstance                                  instance,\n    const VkAllocationCallbacks*                pAllocator)\n{\n   struct instance_data *instance_data = FIND(struct instance_data, instance);\n   instance_data_map_physical_devices(instance_data, false);\n   instance_data->vtable.DestroyInstance(instance, pAllocator);\n#ifdef __linux__\n   if (!is_blacklisted())\n      stop_notifier(instance_data->notifier);\n#endif\n   destroy_instance_data(instance_data);\n}\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\nstatic VkResult overlay_CreateWaylandSurfaceKHR(\n   VkInstance                                  instance,\n   const VkWaylandSurfaceCreateInfoKHR*        pCreateInfo,\n   const VkAllocationCallbacks*                pAllocator,\n   VkSurfaceKHR*                               pSurface\n)\n{\n   VkResult ret;\n   struct instance_data *instance_data = FIND(struct instance_data, instance);\n   HUDElements.display_server = HUDElements.display_servers::WAYLAND;\n   ret = instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);\n   if (ret == VK_SUCCESS)\n      init_wayland_data(pCreateInfo->display, (void *) *pSurface);\n   return ret;\n}\n\nstatic void overlay_DestroySurfaceKHR(\n   VkInstance                                  instance,\n   VkSurfaceKHR                                surface,\n   const VkAllocationCallbacks*                pAllocator\n)\n{\n   struct instance_data *instance_data = FIND(struct instance_data, instance);\n\n   wayland_data_unref(NULL, (void *) surface);\n   instance_data->vtable.DestroySurfaceKHR(instance, surface, pAllocator);\n}\n#endif\n\nextern \"C\" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,\n                                                                             const char *funcName);\nextern \"C\" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,\n                                                                               const char *funcName);\n\nstatic const struct {\n   const char *name;\n   void *ptr;\n} name_to_funcptr_map[] = {\n   { \"vkGetInstanceProcAddr\", (void *) overlay_GetInstanceProcAddr },\n   { \"vkGetDeviceProcAddr\", (void *) overlay_GetDeviceProcAddr },\n#define ADD_HOOK(fn) { \"vk\" # fn, (void *) overlay_ ## fn }\n#define ADD_ALIAS_HOOK(alias, fn) { \"vk\" # alias, (void *) overlay_ ## fn }\n   ADD_HOOK(AllocateCommandBuffers),\n   ADD_HOOK(FreeCommandBuffers),\n   ADD_HOOK(ResetCommandBuffer),\n   ADD_HOOK(BeginCommandBuffer),\n   ADD_HOOK(EndCommandBuffer),\n   ADD_HOOK(CmdExecuteCommands),\n\n#ifdef VK_USE_PLATFORM_WAYLAND_KHR\n   ADD_HOOK(CreateWaylandSurfaceKHR),\n   ADD_HOOK(DestroySurfaceKHR),\n#endif\n   ADD_HOOK(CreateSwapchainKHR),\n   ADD_HOOK(QueuePresentKHR),\n   ADD_HOOK(DestroySwapchainKHR),\n   ADD_HOOK(CreateSampler),\n\n   ADD_HOOK(QueueSubmit),\n\n   ADD_HOOK(CreateDevice),\n   ADD_HOOK(DestroyDevice),\n\n   ADD_HOOK(CreateInstance),\n   ADD_HOOK(DestroyInstance),\n#undef ADD_HOOK\n};\n\nstatic void *find_ptr(const char *name)\n{\n    std::string f(name);\n\n    if (is_blacklisted() && (f != \"vkCreateInstance\" && f != \"vkDestroyInstance\" && f != \"vkCreateDevice\" && f != \"vkDestroyDevice\"))\n    {\n        return NULL;\n    }\n\n   for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) {\n      if (strcmp(name, name_to_funcptr_map[i].name) == 0)\n         return name_to_funcptr_map[i].ptr;\n   }\n\n   return NULL;\n}\n\nextern \"C\" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev,\n                                                                             const char *funcName)\n{\n   init_spdlog();\n   void *ptr = find_ptr(funcName);\n   if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);\n\n   if (dev == NULL) return NULL;\n\n   struct device_data *device_data = FIND(struct device_data, dev);\n   if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL;\n   return device_data->vtable.GetDeviceProcAddr(dev, funcName);\n}\n\nextern \"C\" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance,\n                                                                               const char *funcName)\n{\n   init_spdlog();\n   void *ptr = find_ptr(funcName);\n   if (ptr) return reinterpret_cast<PFN_vkVoidFunction>(ptr);\n\n   if (instance == NULL) return NULL;\n\n   struct instance_data *instance_data = FIND(struct instance_data, instance);\n   if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL;\n   return instance_data->vtable.GetInstanceProcAddr(instance, funcName);\n}\n"
  },
  {
    "path": "src/wayland_hook.h",
    "content": "#include <wayland-client.h>\n#include <set>\n#include <vector>\n\n#ifndef KeySym\ntypedef unsigned long KeySym;\n#endif\n\nextern void* wl_handle;\n\nbool has_wayland_display(struct wl_display *display);\nbool wayland_has_keys_pressed(const std::vector<KeySym>& keys);\nvoid init_wayland_data(struct wl_display *display, void *vk_surface);\nvoid wayland_data_unref(struct wl_display *display, void *vk_surface);\nvoid update_wl_queue();\n"
  },
  {
    "path": "src/wayland_keybinds.cpp",
    "content": "#include <cstdint>\n#include <cstring>\n#include <set>\n#include <unistd.h>\n#include <map>\n#include <wayland-client.h>\n#include <xkbcommon/xkbcommon.h>\n#include <sys/mman.h>\n#include <dlfcn.h>\n\n#include \"wayland_hook.h\"\n#include \"real_dlsym.h\"\n#include \"keybinds.h\"\n\nvoid* wl_handle = NULL;\nstruct xkb_context *context_xkb = NULL;\n\nstruct wayland_display\n{\n    int ref;\n    struct wl_event_queue *queue;\n    struct wl_seat *seat;\n    struct wl_keyboard *keyboard;\n    struct xkb_keymap *keymap_xkb;\n    struct xkb_state *state_xkb;\n    std::set<void *> vk_surfaces;\n    std::set<KeySym> wl_pressed_keys;\n\n    wayland_display()\n    {\n        ref = 1;\n        queue = NULL;\n        keyboard = NULL;\n        keymap_xkb = NULL;\n        state_xkb = NULL;\n        seat = NULL;\n    }\n\n    ~wayland_display()\n    {\n        wl_pressed_keys.clear();\n        vk_surfaces.clear();\n        wl_seat_destroy(this->seat);\n        wl_keyboard_destroy(this->keyboard);\n        wl_event_queue_destroy(this->queue);\n        if (this->keymap_xkb)\n            xkb_keymap_unref(this->keymap_xkb);\n        if (this->state_xkb)\n            xkb_state_unref(this->state_xkb);\n    }\n};\n\nstd::map<struct wl_display *, wayland_display> displays;\n\n// fixes wl_array_for_each with C++\n#ifdef wl_array_for_each\n#undef wl_array_for_each\n#define wl_array_for_each(pos, array)\t\t\t\t\t\\\nfor (pos = (decltype(pos)) (array)->data;\t\t\t\t\\\n    (array)->size != 0 &&\t\t\t\t\t\\\n    (const char *) pos < ((const char *) (array)->data + (array)->size); \\\n    (pos)++)\n#endif\n\nstatic void seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps);\nstatic void seat_handle_name(void *data, struct wl_seat *seat, const char *name) {}\n\nstruct wl_seat_listener seat_listener {\n    .capabilities = seat_handle_capabilities,\n    .name = seat_handle_name,\n};\n\nstatic void registry_handle_global(void *data, struct wl_registry* registry, uint32_t name, const char *interface, uint32_t version)\n{\n    if (!data) return;\n    struct wayland_display *wayland = (wayland_display *)data;\n    if (strcmp(interface, wl_seat_interface.name) == 0 && !wayland->seat)\n    {\n        wayland->seat = (struct wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, version < 5 ? version : 5);\n        wl_seat_add_listener(wayland->seat, &seat_listener, data);\n    }\n}\n\nstatic void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name){}\n\nstatic void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size)\n{\n    wayland_display *wayland = (wayland_display *)data;\n    char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);\n\n    if (!context_xkb)\n        context_xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);\n\n    if (wayland->keymap_xkb && wayland->state_xkb)\n    {\n        xkb_keymap_unref(wayland->keymap_xkb);\n        xkb_state_unref(wayland->state_xkb);\n        wayland->keymap_xkb = NULL;\n        wayland->state_xkb = NULL;\n    }\n\n    wayland->keymap_xkb = xkb_keymap_new_from_string(\n            context_xkb, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1,\n            XKB_KEYMAP_COMPILE_NO_FLAGS);\n\n    wayland->state_xkb = xkb_state_new(wayland->keymap_xkb);\n\n    munmap((void*)map_shm, size);\n    close(fd);\n}\n\nstatic void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)\n{\n    if (!data) return;\n\n    wayland_display *wayland = (wayland_display *)data;\n\n    if (!wayland->state_xkb) return;\n\n    uint32_t *key;\n    wl_array_for_each(key, keys)\n    {\n        xkb_keycode_t keycode = *key + 8;\n        xkb_keysym_t keysym = xkb_state_key_get_one_sym(wayland->state_xkb, keycode);\n        wayland->wl_pressed_keys.insert(keysym);\n    }\n}\n\nstatic void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface)\n{\n    wayland_display *wayland = (wayland_display *)data;\n    wayland->wl_pressed_keys.clear();\n}\n\nstatic void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)\n{\n    if (!data) return;\n\n    wayland_display *wayland = (wayland_display *)data;\n\n    if (!wayland->state_xkb) return;\n\n    xkb_keycode_t keycode = key + 8;\n    xkb_keysym_t keysym = xkb_state_key_get_one_sym(wayland->state_xkb, keycode);\n\n    if (state) wayland->wl_pressed_keys.insert(keysym);\n    else wayland->wl_pressed_keys.erase(keysym);\n}\n\nstatic void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,\n                                  uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group)\n{\n    if (!data) return;\n\n    wayland_display *wayland = (wayland_display *)data;\n\n    if (!wayland->state_xkb) return;\n\n    xkb_state_update_mask(wayland->state_xkb, depressed, latched, locked, 0, 0, group);\n}\n\nstatic void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){}\n\nstruct wl_registry_listener registry_listener {\n    .global = registry_handle_global,\n    .global_remove = registry_handle_global_remove\n};\n\nstruct wl_keyboard_listener keyboard_listener {\n    .keymap = wl_keyboard_keymap,\n    .enter = wl_keyboard_enter,\n    .leave = wl_keyboard_leave,\n    .key = wl_keyboard_key,\n    .modifiers = wl_keyboard_modifiers,\n    .repeat_info = wl_keyboard_repeat_info\n};\n\nstatic void seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps)\n{\n    if (!data) return;\n    wayland_display *wayland = (wayland_display *)data;\n\n    if (caps & WL_SEAT_CAPABILITY_KEYBOARD)\n    {\n        if (!wayland->keyboard)\n        {\n            wayland->keyboard = wl_seat_get_keyboard(seat);\n            wl_keyboard_add_listener(wayland->keyboard, &keyboard_listener, data);\n        }\n    }\n}\n\nvoid update_wl_queue()\n{\n    for (const auto& display : displays)\n        wl_display_dispatch_queue_pending(display.first, display.second.queue);\n}\n\n// Track vk_surface for reference counting\nvoid init_wayland_data(struct wl_display *display, void *vk_surface)\n{\n    if (!display)\n        return;\n\n    if (!wl_handle)\n        wl_handle = real_dlopen(\"libwayland-client.so.0\", RTLD_LAZY);\n\n    // failed to load\n    if (!wl_handle)\n        return;\n\n    // if we already have the display then just increase its reference count\n    // and add its vk_surface\n    if (has_wayland_display(display))\n    {\n        displays[display].ref++;\n        if (vk_surface)\n            displays[display].vk_surfaces.insert(vk_surface);\n        return;\n    }\n\n    // create a new element\n    displays[display].ref = 1;\n    displays[display].queue = wl_display_create_queue(display);\n    if (vk_surface)\n        displays[display].vk_surfaces.insert(vk_surface);\n    struct wl_display *display_wrapped = (struct wl_display*)wl_proxy_create_wrapper(display);\n    wl_proxy_set_queue((struct wl_proxy*)display_wrapped, displays[display].queue);\n    struct wl_registry *registry = wl_display_get_registry(display_wrapped);\n    wl_proxy_wrapper_destroy(display_wrapped);\n    wl_registry_add_listener(registry, &registry_listener, &displays[display]);\n    wl_display_roundtrip_queue(display, displays[display].queue);\n    wl_display_roundtrip_queue(display, displays[display].queue);\n    wl_registry_destroy(registry);\n}\n\nvoid wayland_data_unref(struct wl_display *display, void *vk_surface)\n{\n    if (has_wayland_display(display))\n    {\n        displays[display].ref--;\n    }\n    // use the VkSurface to remove reference count\n    else if (vk_surface)\n    {\n        for (auto& display : displays)\n        {\n            if (display.second.vk_surfaces.count(vk_surface))\n                display.second.ref--;\n        }\n    }\n\n    // clear out all displays with 0 ref count\n    for (auto it = displays.begin(); it != displays.end(); it++)\n    {\n        if (it->second.ref == 0)\n            it = displays.erase(it);\n\n        if (it == displays.end())\n            break;\n    }\n}\n\nbool has_wayland_display(struct wl_display *display)\n{\n    return displays.find(display) != displays.end();\n}\n\nbool wayland_has_keys_pressed(const std::vector<KeySym>& keys)\n{\n    std::map<struct wl_display *, size_t> counter;\n    for (const auto& display : displays)\n    {\n        for (const KeySym& k : keys)\n            if (display.second.wl_pressed_keys.count(k))\n                counter[display.first]++;\n    }\n\n    /* if any of the displays has count == keys.size\n        then it has all required keys pressed */\n    for (const auto& count : counter)\n    {\n        if (count.second == keys.size()) return true;\n    }\n\n    return false;\n}\n"
  },
  {
    "path": "src/win/d3d11_hook.cpp",
    "content": "#include \"kiero.h\"\n\n#if KIERO_INCLUDE_D3D11\n\n#include \"d3d11_hook.h\"\n#include <assert.h>\n#include <intrin.h>\n\n#include \"d3d_shared.h\"\n\ntypedef long(__stdcall* Present)(IDXGISwapChain*, UINT, UINT);\nstatic Present oPresent = NULL;\n\nlong __stdcall hkPresent11(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)\n{\n    dx_version = kiero::RenderType::D3D11;\n#ifdef _MSC_VER\n    static auto addr = _ReturnAddress();\n    if(addr == _ReturnAddress()){\n#else\n    static auto addr = __builtin_return_address(0);\n    if(addr == __builtin_return_address(0)){\n#endif\n        d3d_run();\n    }\n\treturn oPresent(pSwapChain, SyncInterval, Flags);\n}\n\nvoid impl::d3d11::init()\n{\n    printf(\"init d3d11\\n\");\n\tauto ret = kiero::bind(8, (void**)&oPresent, reinterpret_cast<void *>(hkPresent11));\n\tassert(ret == kiero::Status::Success);\n    init_d3d_shared();\n}\n\n#endif // KIERO_INCLUDE_D3D11"
  },
  {
    "path": "src/win/d3d11_hook.h",
    "content": "#pragma once\n#ifndef __D3D11_IMPL_H__\n#define __D3D11_IMPL_H__\n#include <d3d11.h>\nnamespace impl\n{\n\tnamespace d3d11\n\t{\n\t\tvoid init();\n\t}\n}\nlong __stdcall hkPresent11(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);\n\n#endif // __D3D11_IMPL_H__"
  },
  {
    "path": "src/win/d3d12_hook.cpp",
    "content": "#include <cstdio>\n#include <cassert>\n#include \"kiero.h\"\n#include \"d3d12_hook.h\"\n#include \"d3d_shared.h\"\n#include \"../overlay.h\"\n\ntypedef long(__fastcall* PresentD3D12) (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags);\nPresentD3D12 oPresentD3D12;\n\nlong __fastcall hkPresent12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags){\n    dx_version = kiero::RenderType::D3D12;\n    d3d_run();\n    return oPresentD3D12(pSwapChain, SyncInterval, Flags);\n}\n\nvoid impl::d3d12::init()\n{\n    printf(\"init d3d12\\n\");\n    auto ret = kiero::bind(140, (void**)&oPresentD3D12, reinterpret_cast<void*>(hkPresent12));\n    assert(ret == kiero::Status::Success);\n\tinit_d3d_shared();\n}"
  },
  {
    "path": "src/win/d3d12_hook.h",
    "content": "#pragma once\n#include <dxgi.h>\n#include <dxgi1_5.h>\n#include <dxgi1_4.h>\n#ifdef _MSC_VER\n    #include <d3d12.h>\n#else\n    #include \"/usr/i686-w64-mingw32/include/d3d12.h\"\n#endif\n#ifndef __D3D12_IMPL_H__\n#define __D3D12_IMPL_H__\n\nnamespace impl\n{\n\tnamespace d3d12\n\t{\n\t\tvoid init();\n\t}\n}\nlong __fastcall hkPresent12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags);\n\n#endif // __D3D12_IMPL_H__"
  },
  {
    "path": "src/win/d3d_shared.cpp",
    "content": "#include \"d3d_shared.h\"\n#include \"overlay.h\"\n\nbool cfg_inited = false;\nImVec2 window_size;\noverlay_params params {};\nstruct swapchain_stats sw_stats {};\nuint32_t vendorID;\nkiero::RenderType::Enum dx_version;\n\nvoid init_d3d_shared(){\n    if (!logger) logger = std::make_unique<Logger>(&params);\n    vendorID = get_device_id_dxgi();\n    if (cfg_inited)\n        return;\n     parse_overlay_config(&params, getenv(\"MANGOHUD_CONFIG\"), false);\n     cfg_inited = true;\n    //  init_cpu_stats(params);\n}\n\nvoid d3d_run(){\n    check_keybinds(params);\n\tupdate_hud_info(sw_stats, params, vendorID);\n}\n"
  },
  {
    "path": "src/win/d3d_shared.h",
    "content": "#include \"../overlay.h\"\n#include \"kiero.h\"\n\nextern bool cfg_inited;\nextern ImVec2 window_size;\nextern struct overlay_params params;\nextern struct swapchain_stats sw_stats;\nextern uint32_t vendorID;\nextern kiero::RenderType::Enum dx_version;\n\nextern void init_d3d_shared(void);\nextern void d3d_run(void);\nextern uint32_t get_device_id_dxgi(void);"
  },
  {
    "path": "src/win/dxgi.cpp",
    "content": "#include \"kiero.h\"\n#include \"windows.h\"\n#include <dxgi.h>\n#include <cstdio>\n#include \"dxgi.h\"\n\n#ifdef _UNICODE\n# define KIERO_TEXT(text) L##text\n#else\n# define KIERO_TEXT(text) text\n#endif\n\nuint32_t get_device_id_dxgi(){\n    HMODULE libDXGI;\n    if ((libDXGI = ::GetModuleHandle(KIERO_TEXT(\"dxgi.dll\"))) == NULL){\n        printf(\"dxgi not found\\n\");\n        return 0;\n    }\n    auto CreateDXGIFactory = reinterpret_cast<decltype(&::CreateDXGIFactory)>(::GetProcAddress(libDXGI, \"CreateDXGIFactory\"));\n    if (!CreateDXGIFactory)\n    {   \n        printf(\"can't create dxgi factory\\n\");\n        return 0;\n    }\n    IDXGIAdapter* dxgi_adapter;\n    IDXGIFactory* dxgi_factory;\n    if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&dxgi_factory) < 0)\n    {\n        printf(\"can't assign factory\\n\");\n        return 0;\n    }\n    DXGI_ADAPTER_DESC AdapterDesc;\n    int i;\n    for (i = 0; SUCCEEDED(dxgi_factory->EnumAdapters(i, &dxgi_adapter)); i++) {\n        dxgi_adapter->GetDesc(&AdapterDesc);\n        if (AdapterDesc.VendorId == 0x10de)\n            return AdapterDesc.VendorId;\n        if (AdapterDesc.VendorId == 0x1002)\n            return AdapterDesc.VendorId;\n        if (AdapterDesc.VendorId == 0x8086)\n            return AdapterDesc.VendorId;\n    }\n    return 0;\n}"
  },
  {
    "path": "src/win/dxgi.h",
    "content": "#pragma once\nuint32_t get_device_id_dxgi();"
  },
  {
    "path": "src/win/kiero.cpp",
    "content": "#include \"kiero.h\"\n#include <windows.h>\n#include <assert.h>\n#include <cstdio>\n\n#if KIERO_INCLUDE_D3D9\n# include <d3d9.h>\n#endif\n\n#if KIERO_INCLUDE_D3D10\n# include <dxgi.h>\n# include <d3d10_1.h>\n# include <d3d10.h>\n#endif\n\n#if KIERO_INCLUDE_D3D11\n# include <dxgi.h>\n# include <d3d11.h>\n#endif\n\n#if KIERO_INCLUDE_D3D12\n# include <dxgi.h>\n#ifdef _MSC_VER\n    #include <d3d12.h>\n#else\n    #include \"/usr/i686-w64-mingw32/include/d3d12.h\"\n#endif\n#endif\n\n#if KIERO_INCLUDE_OPENGL\n# include <gl/GL.h>\n#endif\n\n#if KIERO_INCLUDE_VULKAN\n# include <vulkan/vulkan.h>\n#endif\n\n#if KIERO_USE_MINHOOK\n# include \"MinHook.h\"\n#endif\n\n#ifdef _UNICODE\n# define KIERO_TEXT(text) L##text\n#else\n# define KIERO_TEXT(text) text\n#endif\n\n#define KIERO_ARRAY_SIZE(arr) ((size_t)(sizeof(arr)/sizeof(arr[0])))\n\nstatic kiero::RenderType::Enum g_renderType = kiero::RenderType::None;\nstatic uint150_t* g_methodsTable = NULL;\n\nkiero::Status::Enum kiero::init(RenderType::Enum _renderType)\n{\n\tif (g_renderType != RenderType::None)\n\t{\n\t\treturn Status::AlreadyInitializedError;\n\t}\n\n\tif (_renderType != RenderType::None)\n\t{\n\t\tif (_renderType >= RenderType::D3D9 && _renderType <= RenderType::D3D12)\n\t\t{\n\t\t\tWNDCLASSEX windowClass;\n\t\t\twindowClass.cbSize = sizeof(WNDCLASSEX);\n\t\t\twindowClass.style = CS_HREDRAW | CS_VREDRAW;\n\t\t\twindowClass.lpfnWndProc = DefWindowProc;\n\t\t\twindowClass.cbClsExtra = 0;\n\t\t\twindowClass.cbWndExtra = 0;\n\t\t\twindowClass.hInstance = GetModuleHandle(NULL);\n\t\t\twindowClass.hIcon = NULL;\n\t\t\twindowClass.hCursor = NULL;\n\t\t\twindowClass.hbrBackground = NULL;\n\t\t\twindowClass.lpszMenuName = NULL;\n\t\t\twindowClass.lpszClassName = KIERO_TEXT(\"Kiero\");\n\t\t\twindowClass.hIconSm = NULL;\n\n\t\t\t::RegisterClassEx(&windowClass);\n\n\t\t\tHWND window = ::CreateWindow(windowClass.lpszClassName, KIERO_TEXT(\"Kiero DirectX Window\"), WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL);\n\n\t\t\tif (_renderType == RenderType::D3D9)\n\t\t\t{\n#if KIERO_INCLUDE_D3D9\n\t\t\t\tHMODULE libD3D9;\n\t\t\t\tif ((libD3D9 = ::GetModuleHandle(KIERO_TEXT(\"d3d9.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tvoid* Direct3DCreate9;\n\t\t\t\tif ((Direct3DCreate9 = ::GetProcAddress(libD3D9, \"Direct3DCreate9\")) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tLPDIRECT3D9 direct3D9;\n\t\t\t\tif ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tD3DDISPLAYMODE displayMode;\n\t\t\t\tif (direct3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tD3DPRESENT_PARAMETERS params;\n\t\t\t\tparams.BackBufferWidth = 0;\n\t\t\t\tparams.BackBufferHeight = 0;\n\t\t\t\tparams.BackBufferFormat = displayMode.Format;\n\t\t\t\tparams.BackBufferCount = 0;\n\t\t\t\tparams.MultiSampleType = D3DMULTISAMPLE_NONE;\n\t\t\t\tparams.MultiSampleQuality = NULL;\n\t\t\t\tparams.SwapEffect = D3DSWAPEFFECT_DISCARD;\n\t\t\t\tparams.hDeviceWindow = window;\n\t\t\t\tparams.Windowed = 1;\n\t\t\t\tparams.EnableAutoDepthStencil = 0;\n\t\t\t\tparams.AutoDepthStencilFormat = D3DFMT_UNKNOWN;\n\t\t\t\tparams.Flags = NULL;\n\t\t\t\tparams.FullScreen_RefreshRateInHz = 0;\n\t\t\t\tparams.PresentationInterval = 0;\n\n\t\t\t\tLPDIRECT3DDEVICE9 device;\n\t\t\t\tif (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, &params, &device) < 0)\n\t\t\t\t{\n\t\t\t\t\tdirect3D9->Release();\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(119, sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable, *(uint150_t**)device, 119 * sizeof(uint150_t));\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tdirect3D9->Release();\n\t\t\t\tdirect3D9 = NULL;\n\n\t\t\t\tdevice->Release();\n\t\t\t\tdevice = NULL;\n\n\t\t\t\tg_renderType = RenderType::D3D9;\n\n\t\t\t\t::DestroyWindow(window);\n\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\t\t\telse if (_renderType == RenderType::D3D10)\n\t\t\t{\n#if KIERO_INCLUDE_D3D10\n\t\t\t\tHMODULE libDXGI;\n\t\t\t\tHMODULE libD3D10;\n\t\t\t\tif ((libDXGI = ::GetModuleHandle(KIERO_TEXT(\"dxgi.dll\"))) == NULL || (libD3D10 = ::GetModuleHandle(KIERO_TEXT(\"d3d10.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tvoid* CreateDXGIFactory;\n\t\t\t\tif ((CreateDXGIFactory = ::GetProcAddress(libDXGI, \"CreateDXGIFactory\")) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tIDXGIFactory* factory;\n\t\t\t\tif (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tIDXGIAdapter* adapter;\n\t\t\t\tif (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tvoid* D3D10CreateDeviceAndSwapChain;\n\t\t\t\tif ((D3D10CreateDeviceAndSwapChain = ::GetProcAddress(libD3D10, \"D3D10CreateDeviceAndSwapChain\")) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tDXGI_RATIONAL refreshRate;\n\t\t\t\trefreshRate.Numerator = 60;\n\t\t\t\trefreshRate.Denominator = 1;\n\n\t\t\t\tDXGI_MODE_DESC bufferDesc;\n\t\t\t\tbufferDesc.Width = 100;\n\t\t\t\tbufferDesc.Height = 100;\n\t\t\t\tbufferDesc.RefreshRate = refreshRate;\n\t\t\t\tbufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tbufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;\n\t\t\t\tbufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;\n\n\t\t\t\tDXGI_SAMPLE_DESC sampleDesc;\n\t\t\t\tsampleDesc.Count = 1;\n\t\t\t\tsampleDesc.Quality = 0;\n\n\t\t\t\tDXGI_SWAP_CHAIN_DESC swapChainDesc;\n\t\t\t\tswapChainDesc.BufferDesc = bufferDesc;\n\t\t\t\tswapChainDesc.SampleDesc = sampleDesc;\n\t\t\t\tswapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n\t\t\t\tswapChainDesc.BufferCount = 1;\n\t\t\t\tswapChainDesc.OutputWindow = window;\n\t\t\t\tswapChainDesc.Windowed = 1;\n\t\t\t\tswapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;\n\t\t\t\tswapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n\n\t\t\t\tIDXGISwapChain* swapChain;\n\t\t\t\tID3D10Device* device;\n\n\t\t\t\tif (((long(__stdcall*)(\n\t\t\t\t\tIDXGIAdapter*,\n\t\t\t\t\tD3D10_DRIVER_TYPE,\n\t\t\t\t\tHMODULE,\n\t\t\t\t\tUINT,\n\t\t\t\t\tUINT,\n\t\t\t\t\tDXGI_SWAP_CHAIN_DESC*,\n\t\t\t\t\tIDXGISwapChain**,\n\t\t\t\t\tID3D10Device**))(D3D10CreateDeviceAndSwapChain))(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &swapChainDesc, &swapChain, &device) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(116, sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 18, *(uint150_t**)device, 98 * sizeof(uint150_t));\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tswapChain->Release();\n\t\t\t\tswapChain = NULL;\n\n\t\t\t\tdevice->Release();\n\t\t\t\tdevice = NULL;\n\n\t\t\t\t::DestroyWindow(window);\n\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\n\t\t\t\tg_renderType = RenderType::D3D10;\n\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\t\t\telse if (_renderType == RenderType::D3D11)\n\t\t\t{\n#if KIERO_INCLUDE_D3D11\n\t\t\t\tHMODULE libD3D11;\n\t\t\t\tif ((libD3D11 = ::GetModuleHandle(KIERO_TEXT(\"d3d11.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tauto D3D11CreateDeviceAndSwapChain = reinterpret_cast<decltype(&::D3D11CreateDeviceAndSwapChain)>(::GetProcAddress(libD3D11, \"D3D11CreateDeviceAndSwapChain\"));\n\t\t\t\tif (!D3D11CreateDeviceAndSwapChain)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tD3D_FEATURE_LEVEL featureLevel;\n\t\t\t\tconst D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 };\n\n\t\t\t\tDXGI_RATIONAL refreshRate;\n\t\t\t\trefreshRate.Numerator = 60;\n\t\t\t\trefreshRate.Denominator = 1;\n\n\t\t\t\tDXGI_MODE_DESC bufferDesc;\n\t\t\t\tbufferDesc.Width = 100;\n\t\t\t\tbufferDesc.Height = 100;\n\t\t\t\tbufferDesc.RefreshRate = refreshRate;\n\t\t\t\tbufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tbufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;\n\t\t\t\tbufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;\n\n\t\t\t\tDXGI_SAMPLE_DESC sampleDesc;\n\t\t\t\tsampleDesc.Count = 1;\n\t\t\t\tsampleDesc.Quality = 0;\n\n\t\t\t\tDXGI_SWAP_CHAIN_DESC swapChainDesc;\n\t\t\t\tswapChainDesc.BufferDesc = bufferDesc;\n\t\t\t\tswapChainDesc.SampleDesc = sampleDesc;\n\t\t\t\tswapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n\t\t\t\tswapChainDesc.BufferCount = 1;\n\t\t\t\tswapChainDesc.OutputWindow = window;\n\t\t\t\tswapChainDesc.Windowed = 1;\n\t\t\t\tswapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;\n\t\t\t\tswapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n\n\t\t\t\tIDXGISwapChain* swapChain;\n\t\t\t\tID3D11Device* device;\n\t\t\t\tID3D11DeviceContext* context;\n\n\t\t\t\tif (((long(__stdcall*)(\n\t\t\t\t\tIDXGIAdapter*,\n\t\t\t\t\tD3D_DRIVER_TYPE,\n\t\t\t\t\tHMODULE,\n\t\t\t\t\tUINT,\n\t\t\t\t\tconst D3D_FEATURE_LEVEL*,\n\t\t\t\t\tUINT,\n\t\t\t\t\tUINT,\n\t\t\t\t\tconst DXGI_SWAP_CHAIN_DESC*,\n\t\t\t\t\tIDXGISwapChain**,\n\t\t\t\t\tID3D11Device**,\n\t\t\t\t\tD3D_FEATURE_LEVEL*,\n\t\t\t\t\tID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 2, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(205, sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 18, *(uint150_t**)device, 43 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 18 + 43, *(uint150_t**)context, 144 * sizeof(uint150_t));\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tswapChain->Release();\n\t\t\t\tswapChain = NULL;\n\n\t\t\t\tdevice->Release();\n\t\t\t\tdevice = NULL;\n\n\t\t\t\tcontext->Release();\n\t\t\t\tcontext = NULL;\n\n\t\t\t\t::DestroyWindow(window);\n\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\n\t\t\t\tg_renderType = RenderType::D3D11;\n\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\t\t\telse if (_renderType == RenderType::D3D12)\n\t\t\t{\n#if KIERO_INCLUDE_D3D12\n\t\t\t\tHMODULE libDXGI;\n\t\t\t\tHMODULE libD3D12;\n\t\t\t\tif ((libDXGI = ::GetModuleHandle(KIERO_TEXT(\"dxgi.dll\"))) == NULL || (libD3D12 = ::GetModuleHandle(KIERO_TEXT(\"d3d12.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tauto CreateDXGIFactory = reinterpret_cast<decltype(&::CreateDXGIFactory)>(::GetProcAddress(libDXGI, \"CreateDXGIFactory\"));\n\t\t\t\tif (!CreateDXGIFactory)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tIDXGIFactory* factory;\n\t\t\t\tif (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tIDXGIAdapter* adapter;\n\t\t\t\tif (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tauto D3D12CreateDevice = reinterpret_cast<decltype(&::D3D12CreateDevice)>(::GetProcAddress(libD3D12, \"D3D12CreateDevice\"));\n\t\t\t\tif (!D3D12CreateDevice)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tID3D12Device* device;\n\t\t\t\tif (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&device) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tD3D12_COMMAND_QUEUE_DESC queueDesc;\n\t\t\t\tqueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n\t\t\t\tqueueDesc.Priority = 0;\n\t\t\t\tqueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n\t\t\t\tqueueDesc.NodeMask = 0;\n\n\t\t\t\tID3D12CommandQueue* commandQueue;\n\t\t\t\tif (device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tID3D12CommandAllocator* commandAllocator;\n\t\t\t\tif (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&commandAllocator) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tID3D12GraphicsCommandList* commandList;\n\t\t\t\tif (device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&commandList) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tDXGI_RATIONAL refreshRate;\n\t\t\t\trefreshRate.Numerator = 60;\n\t\t\t\trefreshRate.Denominator = 1;\n\n\t\t\t\tDXGI_MODE_DESC bufferDesc;\n\t\t\t\tbufferDesc.Width = 100;\n\t\t\t\tbufferDesc.Height = 100;\n\t\t\t\tbufferDesc.RefreshRate = refreshRate;\n\t\t\t\tbufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tbufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;\n\t\t\t\tbufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;\n\n\t\t\t\tDXGI_SAMPLE_DESC sampleDesc;\n\t\t\t\tsampleDesc.Count = 1;\n\t\t\t\tsampleDesc.Quality = 0;\n\n\t\t\t\tDXGI_SWAP_CHAIN_DESC swapChainDesc = {};\n\t\t\t\tswapChainDesc.BufferDesc = bufferDesc;\n\t\t\t\tswapChainDesc.SampleDesc = sampleDesc;\n\t\t\t\tswapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n\t\t\t\tswapChainDesc.BufferCount = 2;\n\t\t\t\tswapChainDesc.OutputWindow = window;\n\t\t\t\tswapChainDesc.Windowed = 1;\n\t\t\t\tswapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;\n\t\t\t\tswapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n\n\t\t\t\tIDXGISwapChain* swapChain;\n\t\t\t\tif (factory->CreateSwapChain(commandQueue, &swapChainDesc, &swapChain) < 0)\n\t\t\t\t{\n\t\t\t\t\t::DestroyWindow(window);\n\t\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\t\t\t\t\treturn Status::UnknownError;\n\t\t\t\t}\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(150, sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable, *(uint150_t**)device, 44 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 44, *(uint150_t**)commandQueue, 19 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 44 + 19, *(uint150_t**)commandAllocator, 9 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 44 + 19 + 9, *(uint150_t**)commandList, 60 * sizeof(uint150_t));\n\t\t\t\t::memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint150_t**)swapChain, 18 * sizeof(uint150_t));\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tdevice->Release();\n\t\t\t\tdevice = NULL;\n\n\t\t\t\tcommandQueue->Release();\n\t\t\t\tcommandQueue = NULL;\n\n\t\t\t\tcommandAllocator->Release();\n\t\t\t\tcommandAllocator = NULL;\n\n\t\t\t\tcommandList->Release();\n\t\t\t\tcommandList = NULL;\n\n\t\t\t\tswapChain->Release();\n\t\t\t\tswapChain = NULL;\n\n\t\t\t\t::DestroyWindow(window);\n\t\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\n\t\t\t\tg_renderType = RenderType::D3D12;\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\n\t\t\t::DestroyWindow(window);\n\t\t\t::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance);\n\n\t\t\treturn Status::NotSupportedError;\n\t\t}\n\t\telse if (_renderType != RenderType::Auto)\n\t\t{\n\t\t\tif (_renderType == RenderType::OpenGL)\n\t\t\t{\n#if KIERO_INCLUDE_OPENGL\n\t\t\t\tHMODULE libOpenGL32;\n\t\t\t\tif ((libOpenGL32 = ::GetModuleHandle(KIERO_TEXT(\"opengl32.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tconst char* const methodsNames[] = {\n\t\t\t\t\t\"glAccum\", \"glAlphaFunc\", \"glAreTexturesResident\", \"glArrayElement\", \"glBegin\", \"glBindTexture\", \"glBitmap\", \"glBlendFunc\", \"glCallList\", \"glCallLists\", \"glClear\", \"glClearAccum\",\n\t\t\t\t\t\"glClearColor\", \"glClearDepth\", \"glClearIndex\", \"glClearStencil\", \"glClipPlane\", \"glColor3b\", \"glColor3bv\", \"glColor3d\", \"glColor3dv\", \"glColor3f\", \"glColor3fv\", \"glColor3i\", \"glColor3iv\",\n\t\t\t\t\t\"glColor3s\", \"glColor3sv\", \"glColor3ub\", \"glColor3ubv\", \"glColor3ui\", \"glColor3uiv\", \"glColor3us\", \"glColor3usv\", \"glColor4b\", \"glColor4bv\", \"glColor4d\", \"glColor4dv\", \"glColor4f\",\n\t\t\t\t\t\"glColor4fv\", \"glColor4i\", \"glColor4iv\", \"glColor4s\", \"glColor4sv\", \"glColor4ub\", \"glColor4ubv\", \"glColor4ui\", \"glColor4uiv\", \"glColor4us\", \"glColor4usv\", \"glColorMask\", \"glColorMaterial\",\n\t\t\t\t\t\"glColorPointer\", \"glCopyPixels\", \"glCopyTexImage1D\", \"glCopyTexImage2D\", \"glCopyTexSubImage1D\", \"glCopyTexSubImage2D\", \"glCullFaceglCullFace\", \"glDeleteLists\", \"glDeleteTextures\",\n\t\t\t\t\t\"glDepthFunc\", \"glDepthMask\", \"glDepthRange\", \"glDisable\", \"glDisableClientState\", \"glDrawArrays\", \"glDrawBuffer\", \"glDrawElements\", \"glDrawPixels\", \"glEdgeFlag\", \"glEdgeFlagPointer\",\n\t\t\t\t\t\"glEdgeFlagv\", \"glEnable\", \"glEnableClientState\", \"glEnd\", \"glEndList\", \"glEvalCoord1d\", \"glEvalCoord1dv\", \"glEvalCoord1f\", \"glEvalCoord1fv\", \"glEvalCoord2d\", \"glEvalCoord2dv\",\n\t\t\t\t\t\"glEvalCoord2f\", \"glEvalCoord2fv\", \"glEvalMesh1\", \"glEvalMesh2\", \"glEvalPoint1\", \"glEvalPoint2\", \"glFeedbackBuffer\", \"glFinish\", \"glFlush\", \"glFogf\", \"glFogfv\", \"glFogi\", \"glFogiv\",\n\t\t\t\t\t\"glFrontFace\", \"glFrustum\", \"glGenLists\", \"glGenTextures\", \"glGetBooleanv\", \"glGetClipPlane\", \"glGetDoublev\", \"glGetError\", \"glGetFloatv\", \"glGetIntegerv\", \"glGetLightfv\", \"glGetLightiv\",\n\t\t\t\t\t\"glGetMapdv\", \"glGetMapfv\", \"glGetMapiv\", \"glGetMaterialfv\", \"glGetMaterialiv\", \"glGetPixelMapfv\", \"glGetPixelMapuiv\", \"glGetPixelMapusv\", \"glGetPointerv\", \"glGetPolygonStipple\",\n\t\t\t\t\t\"glGetString\", \"glGetTexEnvfv\", \"glGetTexEnviv\", \"glGetTexGendv\", \"glGetTexGenfv\", \"glGetTexGeniv\", \"glGetTexImage\", \"glGetTexLevelParameterfv\", \"glGetTexLevelParameteriv\",\n\t\t\t\t\t\"glGetTexParameterfv\", \"glGetTexParameteriv\", \"glHint\", \"glIndexMask\", \"glIndexPointer\", \"glIndexd\", \"glIndexdv\", \"glIndexf\", \"glIndexfv\", \"glIndexi\", \"glIndexiv\", \"glIndexs\", \"glIndexsv\",\n\t\t\t\t\t\"glIndexub\", \"glIndexubv\", \"glInitNames\", \"glInterleavedArrays\", \"glIsEnabled\", \"glIsList\", \"glIsTexture\", \"glLightModelf\", \"glLightModelfv\", \"glLightModeli\", \"glLightModeliv\", \"glLightf\",\n\t\t\t\t\t\"glLightfv\", \"glLighti\", \"glLightiv\", \"glLineStipple\", \"glLineWidth\", \"glListBase\", \"glLoadIdentity\", \"glLoadMatrixd\", \"glLoadMatrixf\", \"glLoadName\", \"glLogicOp\", \"glMap1d\", \"glMap1f\",\n\t\t\t\t\t\"glMap2d\", \"glMap2f\", \"glMapGrid1d\", \"glMapGrid1f\", \"glMapGrid2d\", \"glMapGrid2f\", \"glMaterialf\", \"glMaterialfv\", \"glMateriali\", \"glMaterialiv\", \"glMatrixMode\", \"glMultMatrixd\",\n\t\t\t\t\t\"glMultMatrixf\", \"glNewList\", \"glNormal3b\", \"glNormal3bv\", \"glNormal3d\", \"glNormal3dv\", \"glNormal3f\", \"glNormal3fv\", \"glNormal3i\", \"glNormal3iv\", \"glNormal3s\", \"glNormal3sv\",\n\t\t\t\t\t\"glNormalPointer\", \"glOrtho\", \"glPassThrough\", \"glPixelMapfv\", \"glPixelMapuiv\", \"glPixelMapusv\", \"glPixelStoref\", \"glPixelStorei\", \"glPixelTransferf\", \"glPixelTransferi\", \"glPixelZoom\",\n\t\t\t\t\t\"glPointSize\", \"glPolygonMode\", \"glPolygonOffset\", \"glPolygonStipple\", \"glPopAttrib\", \"glPopClientAttrib\", \"glPopMatrix\", \"glPopName\", \"glPrioritizeTextures\", \"glPushAttrib\",\n\t\t\t\t\t\"glPushClientAttrib\", \"glPushMatrix\", \"glPushName\", \"glRasterPos2d\", \"glRasterPos2dv\", \"glRasterPos2f\", \"glRasterPos2fv\", \"glRasterPos2i\", \"glRasterPos2iv\", \"glRasterPos2s\",\n\t\t\t\t\t\"glRasterPos2sv\", \"glRasterPos3d\", \"glRasterPos3dv\", \"glRasterPos3f\", \"glRasterPos3fv\", \"glRasterPos3i\", \"glRasterPos3iv\", \"glRasterPos3s\", \"glRasterPos3sv\", \"glRasterPos4d\",\n\t\t\t\t\t\"glRasterPos4dv\", \"glRasterPos4f\", \"glRasterPos4fv\", \"glRasterPos4i\", \"glRasterPos4iv\", \"glRasterPos4s\", \"glRasterPos4sv\", \"glReadBuffer\", \"glReadPixels\", \"glRectd\", \"glRectdv\", \"glRectf\",\n\t\t\t\t\t\"glRectfv\", \"glRecti\", \"glRectiv\", \"glRects\", \"glRectsv\", \"glRenderMode\", \"glRotated\", \"glRotatef\", \"glScaled\", \"glScalef\", \"glScissor\", \"glSelectBuffer\", \"glShadeModel\", \"glStencilFunc\",\n\t\t\t\t\t\"glStencilMask\", \"glStencilOp\", \"glTexCoord1d\", \"glTexCoord1dv\", \"glTexCoord1f\", \"glTexCoord1fv\", \"glTexCoord1i\", \"glTexCoord1iv\", \"glTexCoord1s\", \"glTexCoord1sv\", \"glTexCoord2d\",\n\t\t\t\t\t\"glTexCoord2dv\", \"glTexCoord2f\", \"glTexCoord2fv\", \"glTexCoord2i\", \"glTexCoord2iv\", \"glTexCoord2s\", \"glTexCoord2sv\", \"glTexCoord3d\", \"glTexCoord3dv\", \"glTexCoord3f\", \"glTexCoord3fv\",\n\t\t\t\t\t\"glTexCoord3i\", \"glTexCoord3iv\", \"glTexCoord3s\", \"glTexCoord3sv\", \"glTexCoord4d\", \"glTexCoord4dv\", \"glTexCoord4f\", \"glTexCoord4fv\", \"glTexCoord4i\", \"glTexCoord4iv\", \"glTexCoord4s\",\n\t\t\t\t\t\"glTexCoord4sv\", \"glTexCoordPointer\", \"glTexEnvf\", \"glTexEnvfv\", \"glTexEnvi\", \"glTexEnviv\", \"glTexGend\", \"glTexGendv\", \"glTexGenf\", \"glTexGenfv\", \"glTexGeni\", \"glTexGeniv\", \"glTexImage1D\",\n\t\t\t\t\t\"glTexImage2D\", \"glTexParameterf\", \"glTexParameterfv\", \"glTexParameteri\", \"glTexParameteriv\", \"glTexSubImage1D\", \"glTexSubImage2D\", \"glTranslated\", \"glTranslatef\", \"glVertex2d\",\n\t\t\t\t\t\"glVertex2dv\", \"glVertex2f\", \"glVertex2fv\", \"glVertex2i\", \"glVertex2iv\", \"glVertex2s\", \"glVertex2sv\", \"glVertex3d\", \"glVertex3dv\", \"glVertex3f\", \"glVertex3fv\", \"glVertex3i\", \"glVertex3iv\",\n\t\t\t\t\t\"glVertex3s\", \"glVertex3sv\", \"glVertex4d\", \"glVertex4dv\", \"glVertex4f\", \"glVertex4fv\", \"glVertex4i\", \"glVertex4iv\", \"glVertex4s\", \"glVertex4sv\", \"glVertexPointer\", \"glViewport\"\n\t\t\t\t};\n\n\t\t\t\tsize_t size = KIERO_ARRAY_SIZE(methodsNames);\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t));\n\n\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t{\n\t\t\t\t\tg_methodsTable[i] = (uint150_t)::GetProcAddress(libOpenGL32, methodsNames[i]);\n\t\t\t\t}\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tg_renderType = RenderType::OpenGL;\n\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\t\t\telse if (_renderType == RenderType::Vulkan)\n\t\t\t{\n#if KIERO_INCLUDE_VULKAN\n\t\t\t\tHMODULE libVulkan;\n\t\t\t\tif ((libVulkan = GetModuleHandle(KIERO_TEXT(\"vulkan-1.dll\"))) == NULL)\n\t\t\t\t{\n\t\t\t\t\treturn Status::ModuleNotFoundError;\n\t\t\t\t}\n\n\t\t\t\tconst char* const methodsNames[] = {\n\t\t\t\t\t\"vkCreateInstance\", \"vkDestroyInstance\", \"vkEnumeratePhysicalDevices\", \"vkGetPhysicalDeviceFeatures\", \"vkGetPhysicalDeviceFormatProperties\", \"vkGetPhysicalDeviceImageFormatProperties\",\n\t\t\t\t\t\"vkGetPhysicalDeviceProperties\", \"vkGetPhysicalDeviceQueueFamilyProperties\", \"vkGetPhysicalDeviceMemoryProperties\", \"vkGetInstanceProcAddr\", \"vkGetDeviceProcAddr\", \"vkCreateDevice\",\n\t\t\t\t\t\"vkDestroyDevice\", \"vkEnumerateInstanceExtensionProperties\", \"vkEnumerateDeviceExtensionProperties\", \"vkEnumerateDeviceLayerProperties\", \"vkGetDeviceQueue\", \"vkQueueSubmit\", \"vkQueueWaitIdle\",\n\t\t\t\t\t\"vkDeviceWaitIdle\", \"vkAllocateMemory\", \"vkFreeMemory\", \"vkMapMemory\", \"vkUnmapMemory\", \"vkFlushMappedMemoryRanges\", \"vkInvalidateMappedMemoryRanges\", \"vkGetDeviceMemoryCommitment\",\n\t\t\t\t\t\"vkBindBufferMemory\", \"vkBindImageMemory\", \"vkGetBufferMemoryRequirements\", \"vkGetImageMemoryRequirements\", \"vkGetImageSparseMemoryRequirements\", \"vkGetPhysicalDeviceSparseImageFormatProperties\",\n\t\t\t\t\t\"vkQueueBindSparse\", \"vkCreateFence\", \"vkDestroyFence\", \"vkResetFences\", \"vkGetFenceStatus\", \"vkWaitForFences\", \"vkCreateSemaphore\", \"vkDestroySemaphore\", \"vkCreateEvent\", \"vkDestroyEvent\",\n\t\t\t\t\t\"vkGetEventStatus\", \"vkSetEvent\", \"vkResetEvent\", \"vkCreateQueryPool\", \"vkDestroyQueryPool\", \"vkGetQueryPoolResults\", \"vkCreateBuffer\", \"vkDestroyBuffer\", \"vkCreateBufferView\", \"vkDestroyBufferView\",\n\t\t\t\t\t\"vkCreateImage\", \"vkDestroyImage\", \"vkGetImageSubresourceLayout\", \"vkCreateImageView\", \"vkDestroyImageView\", \"vkCreateShaderModule\", \"vkDestroyShaderModule\", \"vkCreatePipelineCache\",\n\t\t\t\t\t\"vkDestroyPipelineCache\", \"vkGetPipelineCacheData\", \"vkMergePipelineCaches\", \"vkCreateGraphicsPipelines\", \"vkCreateComputePipelines\", \"vkDestroyPipeline\", \"vkCreatePipelineLayout\",\n\t\t\t\t\t\"vkDestroyPipelineLayout\", \"vkCreateSampler\", \"vkDestroySampler\", \"vkCreateDescriptorSetLayout\", \"vkDestroyDescriptorSetLayout\", \"vkCreateDescriptorPool\", \"vkDestroyDescriptorPool\",\n\t\t\t\t\t\"vkResetDescriptorPool\", \"vkAllocateDescriptorSets\", \"vkFreeDescriptorSets\", \"vkUpdateDescriptorSets\", \"vkCreateFramebuffer\", \"vkDestroyFramebuffer\", \"vkCreateRenderPass\", \"vkDestroyRenderPass\",\n\t\t\t\t\t\"vkGetRenderAreaGranularity\", \"vkCreateCommandPool\", \"vkDestroyCommandPool\", \"vkResetCommandPool\", \"vkAllocateCommandBuffers\", \"vkFreeCommandBuffers\", \"vkBeginCommandBuffer\", \"vkEndCommandBuffer\",\n\t\t\t\t\t\"vkResetCommandBuffer\", \"vkCmdBindPipeline\", \"vkCmdSetViewport\", \"vkCmdSetScissor\", \"vkCmdSetLineWidth\", \"vkCmdSetDepthBias\", \"vkCmdSetBlendConstants\", \"vkCmdSetDepthBounds\",\n\t\t\t\t\t\"vkCmdSetStencilCompareMask\", \"vkCmdSetStencilWriteMask\", \"vkCmdSetStencilReference\", \"vkCmdBindDescriptorSets\", \"vkCmdBindIndexBuffer\", \"vkCmdBindVertexBuffers\", \"vkCmdDraw\", \"vkCmdDrawIndexed\",\n\t\t\t\t\t\"vkCmdDrawIndirect\", \"vkCmdDrawIndexedIndirect\", \"vkCmdDispatch\", \"vkCmdDispatchIndirect\", \"vkCmdCopyBuffer\", \"vkCmdCopyImage\", \"vkCmdBlitImage\", \"vkCmdCopyBufferToImage\", \"vkCmdCopyImageToBuffer\",\n\t\t\t\t\t\"vkCmdUpdateBuffer\", \"vkCmdFillBuffer\", \"vkCmdClearColorImage\", \"vkCmdClearDepthStencilImage\", \"vkCmdClearAttachments\", \"vkCmdResolveImage\", \"vkCmdSetEvent\", \"vkCmdResetEvent\", \"vkCmdWaitEvents\",\n\t\t\t\t\t\"vkCmdPipelineBarrier\", \"vkCmdBeginQuery\", \"vkCmdEndQuery\", \"vkCmdResetQueryPool\", \"vkCmdWriteTimestamp\", \"vkCmdCopyQueryPoolResults\", \"vkCmdPushConstants\", \"vkCmdBeginRenderPass\", \"vkCmdNextSubpass\",\n\t\t\t\t\t\"vkCmdEndRenderPass\", \"vkCmdExecuteCommands\"\n\t\t\t\t};\n\n\t\t\t\tsize_t size = KIERO_ARRAY_SIZE(methodsNames);\n\n\t\t\t\tg_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t));\n\n\t\t\t\tfor (int i = 0; i < size; i++)\n\t\t\t\t{\n\t\t\t\t\tg_methodsTable[i] = (uint150_t)::GetProcAddress(libVulkan, methodsNames[i]);\n\t\t\t\t}\n\n#if KIERO_USE_MINHOOK\n\t\t\t\tMH_Initialize();\n#endif\n\n\t\t\t\tg_renderType = RenderType::Vulkan;\n\n\t\t\t\treturn Status::Success;\n#endif\n\t\t\t}\n\n\t\t\treturn Status::NotSupportedError;\n\t\t}\n\t}\n\n\treturn Status::Success;\n}\n\nvoid kiero::shutdown()\n{\n\tif (g_renderType != RenderType::None)\n\t{\n#if KIERO_USE_MINHOOK\n\t\tMH_DisableHook(MH_ALL_HOOKS);\n#endif\n\n\t\t::free(g_methodsTable);\n\t\tg_methodsTable = NULL;\n\t\tg_renderType = RenderType::None;\n\t}\n}\n\nkiero::Status::Enum kiero::bind(uint16_t _index, void** _original, void* _function)\n{\n\t// TODO: Need own detour function\n\n\tassert(_original != NULL && _function != NULL);\n\n\tif (g_renderType != RenderType::None)\n\t{\n#if KIERO_USE_MINHOOK\n\t\tvoid* target = (void*)g_methodsTable[_index];\n\t\tif (MH_CreateHook(target, _function, _original) != MH_OK || MH_EnableHook(target) != MH_OK)\n\t\t{\n\t\t\treturn Status::UnknownError;\n\t\t}\n#endif\n\n\t\treturn Status::Success;\n\t}\n\n\treturn Status::NotInitializedError;\n}\n\nvoid kiero::unbind(uint16_t _index)\n{\n\tif (g_renderType != RenderType::None)\n\t{\n#if KIERO_USE_MINHOOK\n\t\tMH_DisableHook((void*)g_methodsTable[_index]);\n#endif\n\t}\n}\n\nkiero::RenderType::Enum kiero::getRenderType()\n{\n\treturn g_renderType;\n}\n\nuint150_t* kiero::getMethodsTable()\n{\n\treturn g_methodsTable;\n} "
  },
  {
    "path": "src/win/kiero.h",
    "content": "#ifndef __KIERO_H__\n#define __KIERO_H__\n\n#include <stdint.h>\n\n#define KIERO_VERSION \"1.2.10\"\n\n#define KIERO_INCLUDE_D3D9   0 // 1 if you need D3D9 hook\n#define KIERO_INCLUDE_D3D10  0 // 1 if you need D3D10 hook\n#define KIERO_INCLUDE_D3D11  1 // 1 if you need D3D11 hook\n#define KIERO_INCLUDE_D3D12  1 // 1 if you need D3D12 hook\n#define KIERO_INCLUDE_OPENGL 0 // 1 if you need OpenGL hook\n#define KIERO_INCLUDE_VULKAN 1 // 1 if you need Vulkan hook\n#define KIERO_USE_MINHOOK    1 // 1 if you will use kiero::bind function\n\n#define KIERO_ARCH_X64 0\n#define KIERO_ARCH_X86 0\n\n#if defined(_M_X64)\t\n# undef  KIERO_ARCH_X64\n# define KIERO_ARCH_X64 1\n#else\n# undef  KIERO_ARCH_X86\n# define KIERO_ARCH_X86 1\n#endif\n\n#if KIERO_ARCH_X64\ntypedef uint64_t uint150_t;\n#else\ntypedef uint32_t uint150_t;\n#endif\n\nnamespace kiero\n{\n\tstruct Status\n\t{\n\t\tenum Enum\n\t\t{\n\t\t\tUnknownError = -1,\n\t\t\tNotSupportedError = -2,\n\t\t\tModuleNotFoundError = -3,\n\n\t\t\tAlreadyInitializedError = -4,\n\t\t\tNotInitializedError = -5,\n\n\t\t\tSuccess = 0,\n\t\t};\n\t};\n\n\tstruct RenderType\n\t{\n\t\tenum Enum\n\t\t{\n\t\t\tNone,\n\n\t\t\tD3D9,\n\t\t\tD3D10,\n\t\t\tD3D11,\n\t\t\tD3D12,\n\n\t\t\tOpenGL,\n\t\t\tVulkan,\n\n\t\t\tAuto\n\t\t};\n\t};\n\n\tStatus::Enum init(RenderType::Enum renderType);\n\tvoid shutdown();\n\n\tStatus::Enum bind(uint16_t index, void** original, void* function);\n\tvoid unbind(uint16_t index);\n\n\tRenderType::Enum getRenderType();\n\tuint150_t* getMethodsTable();\n}\n\n#endif // __KIERO_H__"
  },
  {
    "path": "src/win/main.cpp",
    "content": "#include <cstdio>\n#include \"kiero.h\"\n#include <vector>\n#include \"win_shared.h\"\n#if KIERO_INCLUDE_D3D11\n# include \"d3d11_hook.h\"\n#endif\n#if KIERO_INCLUDE_D3D12\n# include \"d3d12_hook.h\"\n#endif\n\n#ifdef _UNICODE\n# define KIERO_TEXT(text) L##text\n#else\n# define KIERO_TEXT(text) text\n#endif\n\nstd::vector<kiero::RenderType::Enum> render_types;\n\nvoid ConsoleSetup()\n{\n\t// With this trick we'll be able to print content to the console, and if we have luck we could get information printed by the game.\n\tAllocConsole();\n\tSetConsoleTitle(\"MangoHud\");\n\tfreopen(\"CONOUT$\", \"w\", stdout);\n\tfreopen(\"CONOUT$\", \"w\", stderr);\n\tfreopen(\"CONIN$\", \"r\", stdin);\n}\n\nvoid renderTypes() {\n    render_types.clear();\n    if (::GetModuleHandle(KIERO_TEXT(\"d3d9.dll\")) != NULL)\n    {\n        render_types.push_back(kiero::RenderType::D3D9);\n    }\n    if (::GetModuleHandle(KIERO_TEXT(\"d3d10.dll\")) != NULL)\n    {\n        render_types.push_back(kiero::RenderType::D3D10);\n    }\n    if (::GetModuleHandle(KIERO_TEXT(\"d3d11.dll\")) != NULL)\n    {\n        render_types.push_back(kiero::RenderType::D3D11);\n    }\n    if (::GetModuleHandle(KIERO_TEXT(\"d3d12.dll\")) != NULL)\n    {\n        render_types.push_back(kiero::RenderType::D3D12);\n    }\n    if (::GetModuleHandle(KIERO_TEXT(\"opengl32.dll\")) != NULL)\n    {\n        render_types.push_back(kiero::RenderType::OpenGL);\n    }\n    for (auto& _type : render_types)\n        kiero::init(_type);\n}\n\nint MainThread()\n{\n    ConsoleSetup();\n    printf(\"MangoHud Attached!\\n\");\n    renderTypes();\n    if (!render_types.empty()){\n        impl::d3d11::init();\n        impl::d3d12::init();\n        return 1;\n    }\n    return 0;\n}\n\nBOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID)\n{\n    \n    DisableThreadLibraryCalls(hInstance);\n\n    switch (fdwReason)\n    {\n    case DLL_PROCESS_ATTACH:\n        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainThread, NULL, 0, NULL);\n        break;\n    }\n\n    return TRUE;\n}"
  },
  {
    "path": "src/win/win_shared.h",
    "content": "#pragma once\n#include \"windows.h\"\nvoid ConsoleSetup();\nvoid renderTypes();\nint MainThread();\nBOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID);"
  },
  {
    "path": "src/winesync.h",
    "content": "#include \"file_utils.h\"\n#include <filesystem.h>\n#include <string>\n#include <spdlog/spdlog.h>\n#include \"hud_elements.h\"\n#include \"overlay.h\"\n\nnamespace fs = ghc::filesystem;\nclass WineSync {\n    private:\n        inline static const std::unordered_map<std::string, std::string> methods {\n            {\"NONE\", \"NONE\"},\n            {\"winesync\", \"Wserver\"},\n            {\"esync\", \"Esync\"},\n            {\"fsync\", \"Fsync\"},\n            {\"ntsync\", \"NTsync\"},\n        };\n\n        pid_t pid;\n        std::string method = \"NONE\";\n        bool inside_wine = true;\n    public:\n        void determine_sync_variant() {\n#ifdef __linux__\n            // check that's were inside wine\n            std::string wineProcess = get_exe_path();\n            auto n = wineProcess.find_last_of('/');\n            std::string preloader = wineProcess.substr(n + 1);\n            if (preloader != \"wine-preloader\" && preloader != \"wine64-preloader\"){\n                inside_wine = false;\n                return;\n            }\n\n            for (auto& [key, val] : methods) {\n                if (lib_loaded(key, pid)) {\n                    method = key;\n                    break;\n                }\n            }\n\n            SPDLOG_DEBUG(\"Wine sync method: {}\", methods.at(method));\n#endif\n        }\n\n        bool valid() {\n            return inside_wine;\n        }\n\n        // return sync method as display name\n        const char* get_method() {\n            return methods.at(method).c_str();\n        }\n\n        void set_pid(pid_t _pid) {\n            if (_pid != pid) {\n                pid = _pid;\n                determine_sync_variant();\n            }\n        }\n};\n\nextern std::unique_ptr<WineSync> winesync_ptr;\n"
  },
  {
    "path": "steamrt.Dockerfile.in",
    "content": "FROM scratch\nADD com.valvesoftware.SteamRuntime.Sdk-amd64,i386-%RUNTIME%-sysroot.tar.gz /\nWORKDIR /build\nRUN \\\nset -e; \\\nmkdir -p /run/systemd; \\\necho 'docker' > /run/systemd/container; \\\nmkdir -p /prep; cd /prep; \\\nif [ -f /usr/bin/python3.5 ]; then \\\n  ln -sf python3.5 /usr/bin/python3; \\\n  curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o get-pip.py; \\\nelse \\\n  curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; \\\nfi; \\\nif [ ! -f /usr/bin/unzip ]; then apt-get update; apt-get -y install unzip; fi; \\\npython3 ./get-pip.py; \\\npip3 install meson mako; \\\ncurl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb; \\\ncurl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl-dev_440.64-0ubuntu1_amd64.deb; \\\ndpkg -i libxnvctrl0_440.64-0ubuntu1_amd64.deb libxnvctrl-dev_440.64-0ubuntu1_amd64.deb; \\\ncd /; rm -fr /prep; \\\n:\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "subprojects/cmocka.wrap",
    "content": "[wrap-git]\nurl = https://gitlab.com/cmocka/cmocka.git\nrevision = 59dc0013f9f29fcf212fe4911c78e734263ce24c\ndepth = 1\nbranch = master"
  },
  {
    "path": "subprojects/imgui.wrap",
    "content": "[wrap-file]\ndirectory = imgui-1.91.6\nsource_url = https://github.com/ocornut/imgui/archive/refs/tags/v1.91.6.tar.gz\nsource_filename = imgui-1.91.6.tar.gz\nsource_hash = c5fbc5dcab1d46064001c3b84d7a88812985cde7e0e9ced03f5677bec1ba502a\npatch_filename = imgui_1.91.6-3_patch.zip\npatch_url = https://wrapdb.mesonbuild.com/v2/imgui_1.91.6-3/get_patch\npatch_hash = 2f7977114ba07d06559aaf8890a92a4ebd25186592d4447954605aaf2244634d\nsource_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/imgui_1.91.6-3/imgui-1.91.6.tar.gz\nwrapdb_version = 1.91.6-3\n\n[provide]\nimgui = imgui_dep\n"
  },
  {
    "path": "subprojects/implot.wrap",
    "content": "[wrap-file]\ndirectory = implot-0.16\nsource_url = https://github.com/epezent/implot/archive/refs/tags/v0.16.zip\nsource_filename = implot-0.16.zip\nsource_hash = 24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708\npatch_filename = implot_0.16-1_patch.zip\npatch_url = https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch\npatch_hash = 1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7\nsource_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/implot_0.16-1/implot-0.16.zip\nwrapdb_version = 0.16-1\n\n[provide]\nimplot = implot_dep\n"
  },
  {
    "path": "subprojects/minhook.wrap",
    "content": "[wrap-git]\nurl = https://github.com/flightlessmango/minhook.git\nrevision = 81d6f8c775b0be984a91ea927b7beadb4f2d9d86\ndepth = 1\nbranch = master"
  },
  {
    "path": "subprojects/packagefiles/vulkan-headers/meson.build",
    "content": "project(\n  'vulkan-headers',\n  'c',\n  license: 'Apache-2.0',\n  version: '1.4.345',\n  meson_version: '>=0.56.0',\n)\n\nvulkan_api_xml = files('registry/vk.xml')\n\nvulkan_headers_dep = declare_dependency(\n  include_directories: include_directories('include'),\n)\n\nmeson.override_dependency('VulkanHeaders', vulkan_headers_dep)\n"
  },
  {
    "path": "subprojects/packagefiles/vulkan-utility-libraries/meson.build",
    "content": "project(\n  'vulkan-utility-libraries',\n  'c',\n  license: 'Apache-2.0',\n  version: '1.4.346',\n  meson_version: '>=0.56.0',\n)\n\nvulkan_utility_libraries_dep = declare_dependency(\n  include_directories: include_directories('include'),\n)\n\nmeson.override_dependency('VulkanUtilityLibraries', vulkan_utility_libraries_dep)\n"
  },
  {
    "path": "subprojects/spdlog.wrap",
    "content": "[wrap-file]\ndirectory = spdlog-1.14.1\nsource_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz\nsource_filename = spdlog-1.14.1.tar.gz\nsource_hash = 1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b\npatch_filename = spdlog_1.14.1-1_patch.zip\npatch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch\npatch_hash = ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c\nsource_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.14.1-1/spdlog-1.14.1.tar.gz\nwrapdb_version = 1.14.1-1\n\n[provide]\nspdlog = spdlog_dep\n"
  },
  {
    "path": "subprojects/vulkan-headers.wrap",
    "content": "[wrap-file]\ndirectory = Vulkan-Headers-1.4.346\nsource_url = https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.346.tar.gz\nsource_filename = vulkan-headers-1.4.346.tar.gz\nsource_hash = 5bb77f5d7b460e255a9e51affc00d64354986b55cf577d8eab28529cad01fc80\npatch_directory = vulkan-headers\n\n[provide]\ndependency_names = VulkanHeaders\n"
  },
  {
    "path": "subprojects/vulkan-utility-libraries.wrap",
    "content": "[wrap-file]\ndirectory = Vulkan-Utility-Libraries-1.4.346\nsource_url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries/archive/v1.4.346.tar.gz\nsource_filename = vulkan-utility-libraries-1.4.346.tar.gz\nsource_hash = 372eb525103ecb4e3a04d030b2a9778ebc67853bbdc82ce6747de3757d432ad9\npatch_directory = vulkan-utility-libraries\n\n[provide]\ndependency_names = VulkanUtilityLibraries\n"
  },
  {
    "path": "tests/params.py",
    "content": "import re\nimport subprocess\n\nclass Test:\n    def __init__(self):\n        self.options = {}\n        self.error_count = 0\n        self.ignore_params = [\"pci_dev\", \"mangoapp_steam\", \"fsr_steam_sharpness\",\n                              \"blacklist\", \"media_player_format\"]\n        # self.files_changed()\n        self.get_options()\n        self.get_param_defaults()\n        self.find_options_in_readme()\n        self.find_options_in_conf()\n\n        if self.error_count > 0:\n            print(f\"number of errors: {self.error_count}\")\n            exit(1)\n\n    def get_options(self):\n        regex = r\"\\((.*?)\\)\"\n        with open('../src/overlay_params.h') as f:\n            for line in f:\n                if (\"OVERLAY_PARAM_BOOL\" in line or \"OVERLAY_PARAM_CUSTOM\"\n                    in line) and not \"#\" in line:\n                    match = re.search(regex, line)\n                    if match:\n                        key = match.group(1)\n                        if key in self.ignore_params:\n                            continue\n                        else:\n                            self.options[key] = None\n\n    def find_options_in_readme(self):\n        with open(\"../README.md\") as f:\n            file = f.read()\n            for option in self.options:\n                if not option in file:\n                    self.error_count += 1\n                    print(f\"Option: {option} is not found in README.md\")\n\n    def find_options_in_conf(self):\n        with open(\"../data/MangoHud.conf\") as f:\n            file = f.read()\n            for option, val in self.options.items():\n\n                if not option in file:\n                    self.error_count += 1\n                    print(f\"Option: {option} is not found in MangoHud.conf\")\n\n                if option in file:\n                    option = \"# \" + option\n                    for line in file.splitlines():\n                        if option in line:\n                            line = line.strip().split(\"=\")\n                            if len(line) != 2:\n                                continue\n\n                            key = line[0].strip(\"#\").strip()\n                            if key not in self.options:\n                                continue\n\n                            value = line[1].strip()\n                            if \",\" in value:\n                                value = value.split(\",\")\n\n                            if self.options[key] != value:\n                                self.error_count += 1\n                                print(f\"Sample config: option: {key} value is not the same as default\")\n                                print(f\"default: {self.options[key]}, config: {value}\")\n                                print(\"\")\n\n    def get_param_defaults(self):\n        # Open the C++ file\n        with open('../src/overlay_params.cpp', 'r') as f:\n            # Read the contents of the file\n            contents = f.read()\n\n            # Define the name of the function to search for\n            function_name = 'set_param_defaults'\n\n            # Define a regular expression to match the function definition\n            function_regex = re.compile(r\"void\\s+\" +\n                                        function_name + r\"\\s*\\(([^)]*)\\)\\s*{(.+?)\\s*}\\s*\\n\",\n                                        re.MULTILINE | re.DOTALL)\n\n            # Find the match of the regular expression in the file contents\n            match = function_regex.search(contents)\n\n            # If the function is found, extract the contents\n            if match:\n                # Extract the contents of the function\n                function_contents = match.group(2)\n                for line in function_contents.splitlines():\n\n                    # FIXME: Some variables get stored as string in a string\n                    if not \"enabled\" in line:\n                        line = line.replace(\"params->\", \"\")\n                        line = line.strip().strip(\";\").split(\"=\")\n                        if len(line) != 2:\n                            continue\n\n                        key = line[0].strip()\n                        value = line[1].strip()\n                        if key not in self.options:\n                            continue\n\n                        # convert to a list if it contains curly bracket\n                        if \"{\" in value:\n                            value = value.replace(\"{\", \"\").replace(\"}\", \"\").strip().split(\", \")\n                            # If option has color in it's name we can assume it's value is\n                            # one or more colors and that they are in binary.\n                            # We want to convert this from binary because the config\n                            # will not be in this format\n                            if \"color\" in key:\n                                value = [hex[2:] for hex in value]\n                                value = [string.upper() for string in value]\n\n                        # same reasoning as above\n                        if \"color\" in key and type(value) is str:\n                            value = value[2:]\n                            value = value.upper()\n\n                        if \"fps_sampling_period\" in key:\n                            value = re.sub(r';\\s*/\\*.*?\\*/', '', value)\n                            value = str(int(int(value) / 1000000))\n\n                        # if value is a list, make sure we don't store str in str\n                        if type(value) == list:\n                            value = [element.strip('\"') for element in value]\n\n                        self.options[key] = value\n\nTest()\n"
  },
  {
    "path": "tests/test_amdgpu.cpp",
    "content": "#include <stdarg.h>\n#include <stddef.h>\n#include <setjmp.h>\n#include <stdint.h>\nextern \"C\" {\n#include <cmocka.h>\n}\n#include \"stdio.h\"\n#include \"../src/amdgpu.h\"\n\n#define UNUSED(x) (void)(x)\n\nstatic void test_amdgpu_verify_metrics(void **state) {\n    UNUSED(state);\n    AMDGPU amdgpu(\"\", 0x744c, 0x1002);\n\n    assert_false(amdgpu.verify_metrics(\"./missing_file\"));\n    // unsupported struct size, format and content revision\n    assert_false(amdgpu.verify_metrics(\"./gpu_metrics_invalid\"));\n    assert_true (amdgpu.verify_metrics(\"./gpu_metrics\"));\n}\n\nstatic void test_amdgpu_get_instant_metrics(void **state) {\n    UNUSED(state);\n    struct amdgpu_common_metrics metrics;\n    AMDGPU amdgpu(\"\", 0x744c, 0x1002);\n    std::string metrics_path;\n    // fail fetch gpu_metrics file\n    metrics_path = \"./missing_file\";\n    amdgpu.get_instant_metrics(&metrics);\n\n    // DGPU\n    metrics_path = \"./gpu_metrics\";\n    metrics = {};\n    amdgpu.get_instant_metrics(&metrics);\n    assert_int_equal(metrics.gpu_load_percent, 64);\n    assert_float_equal(metrics.average_gfx_power_w, 33, 0);\n    assert_float_equal(metrics.average_cpu_power_w, 0, 0);\n    assert_int_equal(metrics.current_gfxclk_mhz, 2165);\n    assert_int_equal(metrics.current_uclk_mhz, 1000);\n    assert_int_equal(metrics.gpu_temp_c, 36);\n    assert_int_equal(metrics.soc_temp_c, 0);\n    assert_int_equal(metrics.apu_cpu_temp_c, 0);\n    assert_false(metrics.is_power_throttled);\n    assert_false(metrics.is_current_throttled);\n    assert_false(metrics.is_temp_throttled);\n    assert_false(metrics.is_other_throttled);\n\n    // DGPU\n    metrics_path = \"./gpu_metrics_reserved_throttle_bits\";\n    metrics = {};\n    amdgpu.get_instant_metrics(&metrics);\n    assert_false(metrics.is_power_throttled);\n    assert_false(metrics.is_current_throttled);\n    assert_false(metrics.is_temp_throttled);\n    assert_false(metrics.is_other_throttled);\n\n    metrics_path = \"./gpu_metrics_apu\";\n    metrics = {};\n    amdgpu.get_instant_metrics(&metrics);\n    assert_int_equal(metrics.gpu_load_percent, 100);\n    assert_float_equal(metrics.average_gfx_power_w, 6.161, 0);\n    assert_float_equal(metrics.average_cpu_power_w, 9.235, 0);\n    assert_int_equal(metrics.current_gfxclk_mhz, 1040);\n    assert_int_equal(metrics.current_uclk_mhz, 687);\n    assert_int_equal(metrics.gpu_temp_c, 81);\n    assert_int_equal(metrics.soc_temp_c, 71);\n    assert_int_equal(metrics.apu_cpu_temp_c, 80);\n    assert_true(metrics.is_power_throttled);\n    assert_false(metrics.is_current_throttled);\n    assert_false(metrics.is_temp_throttled);\n    assert_false(metrics.is_other_throttled);\n    // amdgpu binary with everything throttled\n}\n\nstatic void test_amdgpu_get_samples_and_copy(void **state) {\n    UNUSED(state);\n    AMDGPU amdgpu(\"\", 0x744c, 0x1002);\n\n    struct amdgpu_common_metrics metrics_buffer[100];\n    bool gpu_load_needs_dividing = false;  //some GPUs report load as centipercent\n    amdgpu.get_samples_and_copy(metrics_buffer, gpu_load_needs_dividing);\n    gpu_load_needs_dividing = true;\n    amdgpu.get_samples_and_copy(metrics_buffer, gpu_load_needs_dividing);\n}\n\nstatic void test_amdgpu_get_metrics(void **state) {\n    UNUSED(state);\n    AMDGPU amdgpu(\"\", 0x744c, 0x1002);\n\n    amdgpu.copy_metrics();\n}\n\nconst struct CMUnitTest amdgpu_tests[] = {\n    cmocka_unit_test(test_amdgpu_verify_metrics),\n    cmocka_unit_test(test_amdgpu_get_instant_metrics),\n    cmocka_unit_test(test_amdgpu_get_samples_and_copy),\n    cmocka_unit_test(test_amdgpu_get_metrics)\n};\n\nint main(void) {\n    return cmocka_run_group_tests(amdgpu_tests, NULL, NULL);\n}\n"
  },
  {
    "path": "version.h.in",
    "content": "#pragma once\n\n#define MANGOHUD_VERSION \"@VCS_TAG@\"\n"
  }
]